你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> Xcode 7:Storyboard Reference、Strong IBOutlet以及Scene Dock

Xcode 7:Storyboard Reference、Strong IBOutlet以及Scene Dock

編輯:IOS開發基礎

storyboard-iOS-9.png

本文由CocoaChina譯者小袋子(博客)翻譯
原文:Storyboard Reference, Strong IBOutlet, Scene Dock in iOS 9


在這個教程中,我想要聊一些有關於Xcode 7中Interface Builder的新特性,我相信這將會改變你對Storyboards的看法。

Strong 引用的 IBOutlet

Apple已經對Xib和Storyboard文件做了很多優化。並且由於這些優化,你現在可以將IBOutlet定義為strong,而不是weak。Apple曾在上一屆的WWDC上指出這一點,因此讓我們來看一下其中的更多細節。你可以從 這個文檔 中找到管理Nib文件中對象生命周期的章節:

Outlet一般來說應該為weak,除了在nib文件 ( 或者iOS中,storyboard scene) 中的File’s Owner的頂級對象,這個對象可以是strong。你創建的Outlets應該為weak,原因如下:

  • 你創建的一個 view controller 視圖的子視圖或者 window controller 窗體視圖的 Outlets,是對象之間的弱引用,不應該有依賴關系。

  • strong的outlet通常是特殊的framework類(如:UIViewController 視圖的 outlet,或者 NSWindowController 視窗的 outlet)。

正如這個段落所解釋的一樣,view controller視圖的子視圖 outlet應該為 weak,因為這個視圖已經被nib文件的頂級對象所擁有了。然而,當一個Outlet被定義為weak指針時,ARC會在編譯期間調用以下函數:

id objc_storeWeak(id *object, id value);

這個函數把對象的值作為key,並把它添加到table中。這個table被稱為weak table。ARC使用這個table去存儲應用中的所有的weak指針。現在,當對象被deallocated時,ARC將會指向weak table並且將weak引用置為nil。同時,ARC將會調用:

void objc_destroyWeak(id * object);

緊接著,注銷這個對象並再次調用objc_destroyWeak:

objc_storeWeak(id *object, nil);

這種weak引用關聯的生命周期是strong引用的2-3倍。所以,通過避免簡單地定義outlets為strong,使用弱引用是一種運行期間的通用做法。

我想這個決策與已廢棄的viewDidUnload方法有關。直到iOS 5,這個方法被用於清空在低內存環境下的視圖。正如文檔中解釋的那樣:

在iOS 5之前,當發生低內存警告或者當前view controller的視圖不被需要時,在視圖被釋放之後,系統會選擇性地調用這個方法。這個方法讓你可以進行最後的清理工作。如果你的視圖存儲了視圖或者其子視圖的單獨引用,你應該使用這個方法去釋放這些引用。

在那時,定義一個屬性為weak是有意義的,因為這就不用在viewDidUnload額外地釋放對象。但是在iOS 9中,我相信我們已經有足夠的時間去避免使用這個方法。因此,在IBOutlets定義weak是沒意義的。

現在 Storyboard 的幾個限制

Apple是在iOS 5中開始引入storyboards的。在此之前,使用Interface Builder的nib文件是創建UI的唯一途徑。在iOS開發中,單個文件中操縱多個nib文件是很普遍的。然而,為了理解應用流以及view controller如何連接在一起,開發者需要去每一個view controller類內去找出跳轉到下一個界面的橋接點。這是一個非常耗費時間的工序,尤其當你不是應用的原始開發者時。

Apple提出Storyboards用以簡化這個過程,並幫助開發者能夠對整個應用程序流有完全的控制。除此之外,storyboards允許你在一個文件中擁有一個view controller視圖(通過添加 .storyboard文件)。用這種方式,你可以看到整個程序的流狀態,並且能夠方便地理解view controller的連接關系。然而,storyboards也引出了一些問題。把所有的nib文件都放在一個文件中顯然是非常便利並且能完美工作,但是這只是在你為單人開發的前提下。只要你的團隊擴大了,你會使用版本控制,例如git或者subversion,這時你就會討厭storyboards。因為,當把修改合並到一個通用的git branch時,就會產生沖突,而解決此類沖突是很頭疼的。在編譯期間,nib會被編譯成XML文件。所以,為了解決合並沖突,你需要比較兩個巨大的XML文件,並且要嘗試理清哪部分是你修改的,哪部分是你同事修改的。此外,Apple經常修改這個文件格式。所以,試圖去理解並且反轉storyboard格式是非常浪費時間的。

例如,在iNVASIVECODE(這是作者所在的公司),我們傾向於使只用storyboards去構建app原型。我們的設計師能夠在幾個小時內設計出一個能夠在iOS設備上運行的原型,有時候只需要幾分鐘。這樣可以在不寫一行代碼的情況下使用storyboards。所以,storyboards對於構建原型來說是非常方便的,但是不建議在開發期間使用。

另一個storyboard的重要局限是不能添加不屬於一個場景體系的視圖。我個人認為跟前面所說的合並問題相比,這是一個更為致命的限制。只要能夠使用,我必定會使用IB。我喜歡這個,因為這可以避免寫代碼。但是使用storyboards,不能添加場景體系以外的視圖。因此,當我需要額外的視圖時,我就強迫自己去使用nib。

Storyboards還有一個額外的局限就是轉場動畫問題。在iOS 7及之後的iOS 8,Apple提出了在兩個view controller之間定制一個轉場動畫的新方法。當你運行一個segue時,這個新方法需要創建不能使用storyboard的特殊對象。所以,如果你想要添加定制轉場動畫的方法到你的view controllers,你要避免使用storyboards。

但是猜猜看!Xcode 7和iOS 9為我們解決了所有的這些問題。

Storyboard Reference

在Xcode 7中,我們有一個在多個storyboards中組織scenes的新方法,並且能對它們進行引用。讓我們來看一個實踐的例子。下載 這個我已經准備好的例子。打開它,並且選擇Main.storyboard文件。我已經為了准備好了一系列組織在一個tab bar controller下view controller。每一個tab包含一個navigation controller。下面的圖片強調了示例項目的storyboard部分。

storyboard1.png

正如你所看到的那樣,tab bar controller包含了三個navigation controller。每一個navigation controller控制著不同的視圖控制器。現在,想象一下在這個項目裡和其他開發者一起工作。正如我前面描述的那樣,使用同一個storyboard文件是非常令人頭疼的,因為你們每個人都會修改它。你可以把著三個navigation分支分割成三個storyboard文件。然而,當你准備在運行期從一個storyboard跳轉到另外一個時,你必須加載相應的storyboard文件。這需要增加額外的代碼。

xcode 7允許你創建多個storyboards,並且可以方便地操縱它們。選擇頂部的navigation controller 以及兩個view controller,如下圖所示:

21.png

選擇好之後,打開菜單欄的Editor,然後選擇Refactor to Storyboard(如圖)

22.png

為新的storyboard取一個名字(如圖)。我將它命名為First.storyboard。

23.png

點擊保存。正如你所見到的那樣,一個新的storyboard已經被添加到你的項目中了。讓我們回到Main.storyboard,你將會看到如下的對象。

24.png

這個稱之為Storyboard Reference,它確實為新建的First.storyboard的引用,並且替換了先前選擇的三個view controller。最棒的是如果你雙擊storyboard引用,Xcode 7會打開所引用的storyboard。因此,當你想要控制應用流時,你可以方便地導向不同的storyboard。在運行期間,當segue指向的一個Storyboard Reference被執行時,這個被引用的storyboard中的初始化view controller會被加載。此外,Storyboard References還能夠引用相同的storyboard。

另外,你也可以手工創建一個新的storyboard,然後添加一個Storyboard Reference到起始的storyboard中。讓我們來試一下。

創建一個新的storyboard並命名為Third.storyboard。在Main.storyboard文件中,從Object Library中添加新的Storyboard Reference。選擇Storyboard Reference並且打開相應的Attributes Inspector。如下圖所示:

25.png

在這個字段中,選擇你想要引用的storyboard(在我們的例子中是Third)。如果這個字段為空白,則被引用的storyboard是定義的Storyboard Reference。Reference ID指向在目的storyboard中的一個特定scene。如果你置空的話,初始化view controller會加載。

26.png

最後,Bundle字段需要被置為包含目的storyboard的bundle。如果你留空的話,就會使用源storyboard的bundle。

在Third.storyboard文件中,你需要添加一個新的view controller並將其作為初始化的view controller。之後,只要view controller是Main storyboard的一部分,你可以都可以運行app並且導航到那裡。

所有,現在你可以在多個文件裡組織你的storyboard,並且可以保持這些storyboard的引用。此外,每一個storyboard能夠被分配給一個不同的開發者,而你不需要去考慮view controller間的連接組合。這真是非常方便。

Scene Dock and Extra Views

這是我最喜歡的特性。現在,我能夠在storyboard中添加在scene體系外的視圖。為了讓你明白它使如何工作的,我們先創建一個新的項目。將其命名為ExtraView,打開Main storyboard,在頂部的First Responder和Exit之間添加一個新的view。如下圖所示(這個叫做Scene Dock):

storyboard8.png

把這個view的大小調整為 1500×120 像素。然後在這個view的頂層添加一個大小為 240×112 的小view。把這個視圖放到大視圖的中心,然後增加頂部和底部的約束 (constants = 8),寬度約束(constant = 240) 以及水平居中的約束。然後添加一個scrollview到view controller中,將其居中,並添加trailing和leading space約束 (constant = 0),高度約束(constant=128),最後增加垂直居中約束。在ViewController.swift中,添加下列兩個outlet:

@IBOutlet var externalView: UIView! 
@IBOutlet var scrollView: UIScrollView!

將它們連接到scrollview以及外面的view。最後,添加viewDidAppear:方法:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    scrollView.contentSize = externalView.frame.size
    scrollView.addSubview(externalView)
}

然後運行項目,可以看到的是,你現在可以添加額外的視圖(可以任意添加),並且可以在運行期間很方便地加載出來。你可以 下載 這個示例來加深理解。

定制轉場動畫

這是Xcode 7中storyboard另外一個很酷的新特性。具體的細節我將會留到之後發布的文章,這裡我只想先給你一些你能做什麼的想法。如果你在多storyboard項目中選擇任意的action segue,並且打開Attributes Inspector,你將會看到一個新的字段Segue Class,正如下圖所示:

27.png

你可以創建一個UIStoryboardSegue的子類,然後遵從UIViewControllerTransitioningDelegate 協議。然後,在類中實現animationControllerForPresentedController: presentingController: sourceController: 以及 animationControllerForDismissedController:。此外,你還需要創建兩個NSObject的子類,遵從UIViewControllerAnimatedTransitioning delegate。在這些類中,你必須實現兩個方法:transitionDuration: 和 animateTransition:。

我將會在接下來的文章中介紹其中的細節。

總結

Xcode 7的Storyboards增加了很多便利的新特性。我們現在可以創建storyboard references,在scene體系外增加視圖,並且可以使用新的定制視圖轉場動畫。我還討論了為什麼你應該將outlet定義為strong引用而不是weak。


作者介紹

Geppy

Geppy Parziale (@geppyp) is cofounder of InvasiveCode (@invasivecode). He has developed iOS applications and taught iOS development since 2008. He worked at Apple as iOS and OS X Engineer in the Core Recognition team. He has developed several iOS and OS X apps and frameworks for Apple, and many of his development projects are top-grossing iOS apps that are featured in the App Store.

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved