我正在使用 ARC 专门为 iOS 5 开发。 IBOutlet
到 UIView
(和子类)应该是 strong
还是 weak
?
以下:
@property (nonatomic, weak) IBOutlet UIButton *button;
将摆脱所有这些:
- (void)viewDidUnload
{
// ...
self.button = nil;
// ...
}
这样做有什么问题吗?模板使用 strong
和从“Interface Builder”编辑器直接连接到标题时创建的自动生成的属性,但为什么呢? UIViewController
已经有一个对其 view
的 strong
引用,该引用保留了它的子视图。
IBOutletCollection()
不能是 weak
,否则返回为 nil
。
strong
警告,过时的答案:根据 WWDC 2015,此答案不是最新的,正确答案请参阅上面的 accepted answer(Daniel Hall)。这个答案将留作记录。
从 developer library 总结:
从实际的角度来看,在 iOS 和 OS X 中的 outlet 应该被定义为声明的属性。出口通常应该是弱的,除了从文件所有者到 nib 文件中的顶级对象(或者,在 iOS 中,故事板场景)应该是强的。因此,默认情况下,您创建的 Outlets 通常是弱的,因为: 您创建的 Outlets,例如,视图控制器的视图或窗口控制器的窗口的子视图,是不暗示所有权的对象之间的任意引用。强插座经常由框架类指定(例如,UIViewController 的视图插座,或 NSWindowController 的窗口插座)。 @property (weak) IBOutlet MyView *viewContainerSubview; @property (strong) IBOutlet MyOtherClass *topLevelObject;
Apple 当前推荐的最佳实践是让 IBOutlets 强,除非特别需要弱来避免保留周期。正如 Johannes 上面提到的,这在 WWDC 2015 的“在 Interface Builder 中实现 UI 设计”会话中对此进行了评论,其中一位 Apple 工程师说:
我要指出的最后一个选项是存储类型,它可以是强的,也可以是弱的。一般来说,您应该使您的出口变得强大,特别是如果您将出口连接到子视图或视图层次结构并不总是保留的约束。唯一真正需要使插座变弱的情况是,如果您有一个自定义视图引用了视图层次结构中的某些内容,并且通常不建议这样做。
我在 Twitter 上向 IB 团队的一位工程师询问了这个问题,他确认 strong 应该是默认设置,并且正在更新开发人员文档。
https://twitter.com/_danielhall/status/620716996326350848 https://twitter.com/_danielhall/status/620717252216623104
https://i.stack.imgur.com/um2WR.jpg
虽然文档建议在子视图的属性上使用 weak
,但从 iOS 6 开始,似乎可以改用 strong
(默认所有权限定符)。这是由 UIViewController
中的更改引起的不再卸载视图。
在 iOS 6 之前,如果你保持到控制器视图的子视图的强链接,如果视图控制器的主视图被卸载,只要视图控制器在附近,它们就会保留子视图。
从 iOS 6 开始,视图不再被卸载,而是加载一次,然后只要它们的控制器存在就一直存在。所以强大的属性并不重要。它们也不会创建强参考循环,因为它们指向强参考图。
就是说,我在使用之间犹豫不决
@property (nonatomic, weak) IBOutlet UIButton *button;
和
@property (nonatomic) IBOutlet UIButton *button;
在 iOS 6 及更高版本中:
使用 weak 清楚地表明控制器不想要按钮的所有权。
但是在没有视图卸载的情况下,在 iOS 6 中省略 weak 并没有什么坏处,而且更短。有些人可能会指出这也更快,但我还没有遇到过因为 IBOutlets 弱而太慢的应用程序。
不使用弱可能被视为错误。
底线:从 iOS 6 开始,只要我们不使用视图卸载,我们就不会再犯这个错误了。是时候聚会了。 ;)
nil
。
weak
在 ARM64 中要便宜很多:D
weak
属性或 __weak
实例变量是可行的方法。我只是想指出这里出错的可能性较小。至于 weak
在 arm64 上更便宜,我什至没有看到 armv7 上 weak
IBOutlet
的实际性能问题。 :)
strong
也有意义。 strong
仅在您使用视图卸载时才有害,但如今谁会这样做? :)
我看不出有什么问题。在 ARC 之前,我一直将我的 IBOutlets 设为 assign
,因为它们已经被他们的 superview 保留了。正如您所指出的,如果您将它们设为 weak
,则不必在 viewDidUnload 中将它们归零。
一个警告:您可以在 ARC 项目中支持 iOS 4.x,但如果这样做,您将无法使用 weak
,因此您必须将它们设为 assign
,在这种情况下您仍然需要将 viewDidUnload
中的引用设为 nil 以避免出现悬空指针。这是我遇到的一个悬空指针错误的示例:
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];
}
我发现如果我在正确的时间关闭了这个视图并且没有在 viewDidUnload
中将 self.zip 设为 nil,那么委托回调可能会在 self.zip.text 上引发错误的访问异常。
weak
属性不需要在 viewDidUnload
中取消。但是,为什么 Apple 用于创建网点的模板包含 [self setMySubview:nil]
?
出于性能原因,IBOutlet
应该很强大。请参阅Storyboard Reference, Strong IBOutlet, Scene Dock in iOS 9
如本段所述,视图控制器视图的子视图的出口可能很弱,因为这些子视图已经由 nib 文件的顶级对象拥有。但是,当一个 Outlet 被定义为弱指针并设置该指针时,ARC 调用运行时函数: id objc_storeWeak(id *object, id value);这会将指针(对象)添加到使用对象值作为键的表中。该表称为弱表。 ARC 使用此表来存储应用程序的所有弱指针。现在,当对象值被释放时,ARC 将遍历弱表并将弱引用设置为 nil。或者,ARC 可以调用: void objc_destroyWeak(id * object) 然后,对象被取消注册,并且 objc_destroyWeak 再次调用: objc_storeWeak(id *object, nil) 这种与弱引用相关联的簿记可能需要 2-3 倍的时间。发布强参考。因此,弱引用为运行时引入了开销,您可以通过简单地将出口定义为强来避免。
从 Xcode 7 开始,它建议 strong
https://monosnap.com/file/a2uqfmsRjtJyn3p4KtjuTX7XMaDZHu.png
如果您观看 WWDC 2015 会话 407 Implementing UI Designs in Interface Builder,它建议(来自 http://asciiwwdc.com/2015/sessions/407 的转录)
我要指出的最后一个选项是存储类型,它可以是强的,也可以是弱的。一般来说,您应该使您的插座变得强大,特别是如果您将插座连接到子视图或视图层次结构并不总是保留的约束。唯一真正需要使插座变弱的情况是,如果您有一个自定义视图引用了视图层次结构中的某些内容,并且通常不建议这样做。所以我要选择 strong 并且我会点击 connect 这将生成我的出口。
在 iOS 开发中,NIB 加载与 Mac 开发有点不同。
在 Mac 开发中,IBOutlet 通常是一个弱引用:如果你有一个 NSViewController 的子类,那么只有顶层视图会被保留,当你释放控制器时,它的所有子视图和出口都会自动释放。
UiViewController 使用键值编码来设置使用强引用的 outlet。因此,当您释放 UIViewController 时,顶视图将自动释放,但您还必须在 dealloc 方法中释放其所有出口。
In this post from the Big Nerd Ranch,他们涵盖了这个主题,并解释了为什么在 IBOutlet 中使用强引用不是一个好的选择(即使在这种情况下 Apple 推荐使用它)。
我想在这里指出一件事,那就是,尽管 Apple 工程师在他们自己的 WWDC 2015 视频中已经说过:
https://developer.apple.com/videos/play/wwdc2015/407/
苹果在这个问题上不断改变主意,这告诉我们这个问题没有唯一的正确答案。为了表明即使是苹果工程师在这个问题上也存在分歧,看看苹果最近的示例代码,你会看到有些人使用弱,有些人没有。
所有这些都针对 iOS 9 进行了全面更新,并且都使用了弱插座。从中我们了解到 A. 问题并不像某些人所说的那么简单。 B. 苹果一再改变主意,C. 你可以用任何让你开心的东西 :)
特别感谢 Paul Hudson(www.hackingwithsift.com 的作者),他为我提供了澄清,并提供了此答案的参考资料。
我希望这能更好地阐明主题!
小心。
从 WWDC 2015 开始,Implementing UI Designs in Interface Builder 上有一个会话。在 32 分钟左右,他说你总是想让你的 @IBOutlet
strong。
请注意,IBOutletCollection
应该是 @property (strong, nonatomic)
。
copy
,因为它是 NSArray
?
多年来,似乎有些东西发生了变化,现在 Apple 建议总体上使用 strong 。他们的 WWDC 会议的证据在 session 407 - Implementing UI Designs in Interface Builder 中,从 32:30 开始。我对他所说的话的注释是(几乎,如果不完全是引用他的话):
一般来说,出口连接应该是强的,尤其是当我们连接视图层次结构并不总是保留的子视图或约束时
创建自定义视图时可能需要弱插座连接,这些视图对视图层次结构中的备份有一些引用,通常不建议这样做
在其他方面,只要我们的一些自定义视图不创建保留循环,其中一些视图在视图层次结构中向上,它现在应该总是很强大
编辑 :
有些人可能会问这个问题。使用强引用保持它不会创建一个保留周期,因为根视图控制器和拥有视图保持对它的引用?或者为什么会发生这种变化?当他们描述如何从 xib 创建 nib 时,我认为答案在本次演讲的前面。为 VC 和视图创建了一个单独的 nib。我认为这可能是他们改变建议的原因。不过,如果能从 Apple 那里得到更深入的解释,那就太好了。
我认为最重要的信息是:xib 中的元素自动在视图的子视图中。子视图是 NSArray。 NSArray 拥有它的元素。等对他们有很强的指示。所以在大多数情况下你不想创建另一个强指针(IBOutlet)
使用 ARC,您无需在 viewDidUnload
中执行任何操作
不定期副业成功案例分享