本文由CocoaChina譯者小袋子(博客)翻譯
原文:Storyboard Reference, Strong IBOutlet, Scene Dock in iOS 9html
Strong 引用的 IBOutletios
Apple已經對Xib和Storyboard文件作了不少優化。而且因爲這些優化,你如今能夠將IBOutlet定義爲strong,而不是weak。Apple曾在上一屆的WWDC上指出這一點,所以讓咱們來看一下其中的更多細節。你能夠從 這個文檔 中找到管理Nib文件中對象生命週期的章節:git
Outlet通常來講應該爲weak,除了在nib文件 ( 或者iOS中,storyboard scene) 中的File’s Owner的頂級對象,這個對象能夠是strong。你建立的Outlets應該爲weak,緣由以下:web
你建立的一個 view controller 視圖的子視圖或者 window controller 窗體視圖的 Outlets,是對象之間的弱引用,不該該有依賴關係。swift
strong的outlet一般是特殊的framework類(如:UIViewController 視圖的 outlet,或者 NSWindowController 視窗的 outlet)。xcode
正如這個段落所解釋的同樣,view controller視圖的子視圖 outlet應該爲 weak,由於這個視圖已經被nib文件的頂級對象所擁有了。然而,當一個Outlet被定義爲weak指針時,ARC會在編譯期間調用如下函數:app
1
|
id objc_storeWeak(id *object, id value);
|
這個函數把對象的值做爲key,並把它添加到table中。這個table被稱爲weak table。ARC使用這個table去存儲應用中的全部的weak指針。如今,當對象被deallocated時,ARC將會指向weak table而且將weak引用置爲nil。同時,ARC將會調用:ide
1
|
void objc_destroyWeak(id * object);
|
緊接着,註銷這個對象並再次調用objc_destroyWeak:函數
1
|
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部分。
正如你所看到的那樣,tab bar controller包含了三個navigation controller。每個navigation controller控制着不一樣的視圖控制器。如今,想象一下在這個項目裏和其餘開發者一塊兒工做。正如我前面描述的那樣,使用同一個storyboard文件是很是使人頭疼的,由於大家每一個人都會修改它。你能夠把着三個navigation分支分割成三個storyboard文件。然而,當你準備在運行期從一個storyboard跳轉到另一個時,你必須加載相應的storyboard文件。這須要增長額外的代碼。
xcode 7容許你建立多個storyboards,而且能夠方便地操縱它們。選擇頂部的navigation controller 以及兩個view controller,以下圖所示:
選擇好以後,打開菜單欄的Editor,而後選擇Refactor to Storyboard(如圖)
爲新的storyboard取一個名字(如圖)。我將它命名爲First.storyboard。
點擊保存。正如你所見到的那樣,一個新的storyboard已經被添加到你的項目中了。讓咱們回到Main.storyboard,你將會看到以下的對象。
這個稱之爲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。以下圖所示:
在這個字段中,選擇你想要引用的storyboard(在咱們的例子中是Third)。若是這個字段爲空白,則被引用的storyboard是定義的Storyboard Reference。Reference ID指向在目的storyboard中的一個特定scene。若是你置空的話,初始化view controller會加載。
最後,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):
把這個view的大小調整爲 1500×120 像素。而後在這個view的頂層添加一個大小爲 240×112 的小view。把這個視圖放到大視圖的中心,而後增長頂部和底部的約束 (constants = 8),寬度約束(constant = 240) 以及水平居中的約束。而後添加一個scrollview到view controller中,將其居中,並添加trailing和leading space約束 (constant = 0),高度約束(constant=128),最後增長垂直居中約束。在ViewController.swift中,添加下列兩個outlet:
1
2
|
@IBOutlet
var
externalView: UIView!
@IBOutlet
var
scrollView: UIScrollView!
|
將它們鏈接到scrollview以及外面的view。最後,添加viewDidAppear:方法:
1
2
3
4
5
|
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,正以下圖所示:
你能夠建立一個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 andtaught 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.