在ARC下,iboutlet应该是强的还是弱的?

我使用ARC专门为iOS 5开发游戏。IBOutlets到UIViews(和子类)应该是strong还是weak?

以下几点:

@property (nonatomic, weak) IBOutlet UIButton *button;

就能摆脱这一切

- (void)viewDidUnload
{
// ...
self.button = nil;
// ...
}

做这个有什么问题吗?模板使用strong作为从“接口构建器”编辑器直接连接到头部时自动生成的属性,但为什么?UIViewController已经有一个strong引用到它的view,它保留了它的子视图。

129002 次浏览

我看不出有什么问题。在arc之前,我总是将IBOutlets设为assign,因为它们已经被它们的父视图保留了。如果你让他们weak,你不应该在viewDidUnload中nil他们,正如你指出的那样。

警告:你可以支持iOS 4。x在一个ARC项目,但如果你这样做,你不能使用weak,所以你必须使他们assign,在这种情况下,你仍然想nil在viewDidUnload引用,以避免悬空指针。下面是我经历过的一个悬浮指针错误的例子:

UIViewController有一个UITextField表示邮政编码。它使用CLLocationManager反向对用户的位置进行地理编码并设置邮政编码。这是委托回调:

-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
Class geocoderClass = NSClassFromString(@"CLGeocoder");
if (geocoderClass && IsEmpty(self.zip.text)) {
id geocoder = [[geocoderClass alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (self.zip && IsEmpty(self.zip.text)) {
self.zip.text = [[placemarks objectAtIndex:0] postalCode];
}
}];
}
[self.locationManager stopUpdatingLocation];
}

我发现,如果我在正确的时间解散这个视图,没有nil self.zip在viewDidUnload,委托回调可以抛出一个糟糕的访问异常self.zip.text。

在iOS开发中,NIB加载与Mac开发略有不同。

在Mac开发中,IBOutlet通常是一个弱引用:如果你有NSViewController的子类,只有顶级视图会被保留,当你释放控制器时,它的所有子视图和outlet都会自动释放。

UiViewController使用键值编码来设置出口使用强引用。当你dealloc你的UIViewController时,顶视图会自动释放,但你也必须在dealloc方法中释放它所有的outlet。

在这篇来自大书呆子农场的文章中,他们涵盖了这个主题,也解释了为什么在IBOutlet中使用强引用不是一个好的选择(即使在这种情况下苹果推荐它)。

警告,过时的答案:根据WWDC 2015,这个答案不是最新的,正确答案参考上面的接受的答案(丹尼尔·霍尔)。这个答案将被记录下来。


开发库总结:

从实用的角度来看,在iOS和OS X中,outlet应该定义为声明的属性。outlet通常应该是弱的,除了那些从File 's Owner到nib文件(或者在iOS中,storyboard场景)中的顶级对象的outlet应该是强的。因此,在默认情况下,您创建的outlet通常是弱的,因为:

  • 例如,创建到视图控制器的视图的子视图或窗口控制器的窗口的outlet是对象之间的任意引用,并不意味着所有权。

  • 强出口通常由框架类指定(例如,UIViewController的视图出口,或NSWindowController的窗口出口)。

    @property (weak) IBOutlet MyView *viewContainerSubview;
    @property (strong) IBOutlet MyOtherClass *topLevelObject;
    
我认为最重要的信息是: xib中的元素自动位于view的子视图中。Subviews是NSArray。NSArray拥有它的元素。等等都有强指针。所以在大多数情况下,您不希望创建另一个强指针(IBOutlet)

使用ARC,你不需要在viewDidUnload中做任何事情

这是由于在EYZ2中视图不再被卸载所引起的变化。

  • 在ios6之前,如果你保持强链接到控制器视图的子视图,如果视图控制器的主视图被卸载,只要视图控制器还在,那些就会保留子视图。
  • 自iOS 6以来,视图不再被卸载,而是加载一次,然后只要它们的控制器还在,视图就会一直存在。所以强属性无关紧要。它们也不会创建强引用循环,因为它们向下指向强引用图。

也就是说,我在使用之间犹豫不决

@property (nonatomic, weak) IBOutlet UIButton *button;

而且

@property (nonatomic) IBOutlet UIButton *button;

iOS 6及以后版本:

  • 使用weak清楚地表明控制器不想要按钮的所有权。

  • 但是省略weak在没有视图卸载的iOS 6中没有什么坏处,而且更短。有些人可能会指出这也更快,但我还没有遇到过因为weak IBOutlets而太慢的应用程序。

  • 不使用weak可能会被视为错误。

底线:自从iOS 6以来,只要我们不使用视图卸载,我们就不会再犯这个错误了。聚会时间到了。;)

注意,IBOutletCollection应该是@property (strong, nonatomic)

在2015年的WWDC大会上,有一个关于在界面生成器中实现UI设计的会议。在32分钟左右,他说你总是想让你的@IBOutlet <强大的>强大的

目前苹果推荐的最佳实践是IBOutlets为强大的,除非为了避免保留循环特别需要。就像Johannes上面提到的,在2015年WWDC的“在界面生成器中实现UI设计”会议上,一位苹果工程师说:

我想指出的最后一个选项是存储类型,它可以 要么坚强,要么软弱。一般来说,你应该做出口 强,特别是当你连接一个输出到子视图或 约束并不总是会被视图保留 层次结构。唯一真正需要使outlet弱的时候是if 您有一个自定义视图,它引用视图中的备份内容

我在Twitter上向IB团队的一位工程师询问了这个问题,他确认强大的应该是默认值,并且开发人员文档正在更新。

https://twitter.com/_danielhall/status/620716996326350848 # EYZ0 < / p >

这几年似乎发生了一些变化,现在苹果建议一般使用strong。他们的WWDC会议的证据在在界面生成器中实现UI设计中,从32:30开始。我从他的话中摘录(如果不是完全引用的话,也几乎是引用了他的话):

  • 出口连接通常应该是强的,特别是当我们连接的子视图或约束不总是被保留 视图层次< / em > < / p > < /李>

  • 弱出口连接可能在创建自定义视图时需要,该自定义视图有一些引用到视图层次结构中的备份 一般不建议

在其他方面,它应该总是强的只要我们的一些自定义视图没有与视图层次结构中的一些视图创建一个保留循环

编辑:

有些人可能会问这个问题。用强引用保存它是否不会创建一个保留循环作为根视图控制器而所属视图保留对它的引用?或者为什么会发生这种变化? 我想答案在这个演讲的前面,当他们描述如何从xib创建nib时。为VC和视图创建了一个单独的nib。我认为这可能是他们改变建议的原因。不过,如果能从苹果那里得到更深入的解释就好了

出于性能考虑,IBOutlet应该是强的。看到# EYZ1

如本段所述,视图的子视图的出口 控制器视图可以是弱的,因为这些子视图已经是 由nib文件的顶级对象拥有。然而,当Outlet 定义为弱指针并设置指针时,ARC调用 运行时功能:< / p >

# EYZ0

添加指针 (对象)到一个表,使用对象值作为键。这张桌子是 称为弱表。ARC使用这个表来存储所有的 应用程序的弱指针。现在,当对象值是 ARC将遍历弱表并设置弱表 引用nil。ARC也可以调用:

# EYZ0

则对象为 unregistered和objc_destroyWeak再次调用:

# EYZ0

这个簿记相关 弱引用的发布时间比弱引用的发布时间长2-3倍 强引用。因此,弱引用为 可以通过简单地将outlet定义为strong来避免的运行时

在Xcode 7中,它建议使用strong

< img src = " https://monosnap.com/file/a2uqfmsRjtJyn3p4KtjuTX7XMaDZHu.png " >

如果你观看了WWDC 2015的407 在界面生成器中实现UI设计会议,它建议(来自http://asciiwwdc.com/2015/sessions/407)

我想指出的最后一个选项是存储类型,它可以是强类型,也可以是弱类型。

一般来说,你应该让outlet强,特别是当你将outlet连接到子视图或约束时,这些约束并不总是会被视图层次结构保留。

唯一需要将outlet设为弱的情况是,如果你有一个自定义视图,它引用了视图层次结构中的一些东西,通常不建议这样做。

我将选择strong然后点击connect这将生成outlet。

我想在这里指出一件事,那就是,尽管苹果工程师在他们自己的2015年全球开发者大会视频中说过:

https://developer.apple.com/videos/play/wwdc2015/407/ < a href = " https://developer.apple.com/videos/play/wwdc2015/407/ " > < / >

苹果公司在这个问题上一直在改变主意,这告诉我们这个问题没有唯一的正确答案。为了证明就连苹果的工程师在这个问题上也存在分歧,看看苹果最近的一份报告就知道了 示例代码,你会看到有些人使用weak,有些人不用 这个Apple Pay的例子使用了weak: # EYZ0 < / p >

如下图中图的例子所示: # EYZ0 < / p > 与Lister的例子一样: # EYZ0 < / p > 核心位置的例子如下: # EYZ0 < / p > 视图控制器预览示例如下: # EYZ0 < / p > HomeKit的例子如下: # EYZ0 < / p >

所有这些都是针对iOS 9完全更新的,并且都使用弱outlet。这个问题并不像有些人想的那么简单。B.苹果一再改变主意,C.你可以用任何让你高兴的东西:)

特别感谢Paul Hudson (www.hackingwithsift.com的作者),他给了我澄清,以及这个答案的参考资料。

我希望这能更好地阐明主题!

当心