iOS 9系列:Storyboard Reference、Strong IBOutlet以及Scene Dock

1445501965993069.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部分。

1445502506602936.png

正如你所看到的那样,tab bar controller包含了三个navigation controller。每一个navigation controller控制着不同的视图控制器。现在,想象一下在这个项目里和其他开发者一起工作。正如我前面描述的那样,使用同一个storyboard文件是非常令人头疼的,因为你们每个人都会修改它。你可以把着三个navigation分支分割成三个storyboard文件。然而,当你准备在运行期从一个storyboard跳转到另外一个时,你必须加载相应的storyboard文件。这需要增加额外的代码。
xcode 7允许你创建多个storyboards,并且可以方便地操纵它们。选择顶部的navigation controller 以及两个view controller,如下图所示:
1445502568715361.png

选择好之后,打开菜单栏的Editor,然后选择Refactor to Storyboard(如图)
1445502615641502.png

为新的storyboard取一个名字(如图)。我将它命名为First.storyboard。
1445502671957526.png

点击保存。正如你所见到的那样,一个新的storyboard已经被添加到你的项目中了。让我们回到Main.storyboard,你将会看到如下的对象。
1445502704634152.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。如下图所示:
1445502735552734.png

在这个字段中,选择你想要引用的storyboard(在我们的例子中是Third)。如果这个字段为空白,则被引用的storyboard是定义的Storyboard Reference。Reference ID指向在目的storyboard中的一个特定scene。如果你置空的话,初始化view controller会加载。
1445502798712409.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):
1445502912235844.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,正如下图所示:

1445503461774466.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 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.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容