简体   繁体   English

在ARC下,IBOutlets应该强还是弱?

[英]Should IBOutlets be strong or weak under ARC?

I am developing exclusively for iOS 5 using ARC. 我正在使用ARC专为iOS 5开发。 Should IBOutlet s to UIView s (and subclasses) be strong or weak ? IBOutletUIView (和子类)应该strong还是weak

The following: 下列:

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

Would get rid of all of this: 将摆脱所有这些:

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

Are there any problems doing this? 这样做有什么问题吗? The templates are using strong as are the automatically generated properties created when connecting directly to the header from the 'Interface Builder' editor, but why? 从“接口生成器”编辑器直接连接到标题时,模板使用的功能很strong就像自动生成的属性一样,但是为什么? The UIViewController already has a strong reference to its view which retains its subviews. UIViewController已经对其view进行了strong引用,并保留了其子视图。

WARNING, OUTDATED ANSWER : this answer is not up to date as per WWDC 2015, for the correct answer refer to the accepted answer (Daniel Hall) above. 警告,过时的答案 :根据WWDC 2015,此答案不是最新的,有关正确答案,请参阅上面的公认答案 (丹尼尔·霍尔)。 This answer will stay for record. 该答案将留作记录。


Summarized from the developer library : 来自开发人员库的摘要:

From a practical perspective, in iOS and OS X outlets should be defined as declared properties. 从实际的角度来看,在iOS和OS X中,出口应定义为已声明的属性。 Outlets should generally be weak, except for those from File's Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. 出口通常应该较弱,但从文件所有者到笔尖文件(或iOS中的情节提要场景)中顶级对象的出口则应较坚固。 Outlets that you create will therefore typically be weak by default, because: 因此,默认情况下,您创建的插座通常较弱,因为:

  • Outlets that you create to, for example, subviews of a view controller's view or a window controller's window, are arbitrary references between objects that do not imply ownership. 您为视图控制器的子视图或窗口控制器的窗口的子视图创建的出口是对象之间的任意引用,并不表示所有权。

  • The strong outlets are frequently specified by framework classes (for example, UIViewController's view outlet, or NSWindowController's window outlet). 强势出口经常由框架类指定(例如,UIViewController的视图出口或NSWindowController的窗口出口)。

     @property (weak) IBOutlet MyView *viewContainerSubview; @property (strong) IBOutlet MyOtherClass *topLevelObject; 

The current recommended best practice from Apple is for IBOutlets to be strong unless weak is specifically needed to avoid a retain cycle. 苹果公司目前建议的最佳做法是使IBOutlets 强,除非特别需要弱化以避免保留周期。 As Johannes mentioned above, this was commented on in the "Implementing UI Designs in Interface Builder" session from WWDC 2015 where an Apple Engineer said: 正如Johannes所述,在WWDC 2015的“在Interface Builder中实现UI设计”会议中对此进行了评论,其中苹果工程师说:

And the last option I want to point out is the storage type, which can either be strong or weak. 我要指出的最后一个选项是存储类型,可以是强类型或弱类型。 In general you should make your outlet strong, especially if you are connecting an outlet to a subview or to a constraint that's not always going to be retained by the view hierarchy. 通常,您应该使出口坚固,尤其是当您将出口连接到子视图或不总是由视图层次结构保留的约束时。 The only time you really need to make an outlet weak is if you have a custom view that references something back up the view hierarchy and in general that's not recommended. 真正需要弱化出口的唯一情况是,如果您有一个自定义视图,该视图引用了备份视图层次结构的内容,通常不建议这样做。

I asked about this on Twitter to an engineer on the IB team and he confirmed that strong should be the default and that the developer docs are being updated. 我在Twitter上向IB团队的一名工程师询问了此问题,他确认将默认设置为“ 强” ,并且正在更新开发人员文档。

https://twitter.com/_danielhall/status/620716996326350848 https://twitter.com/_danielhall/status/620717252216623104 https://twitter.com/_danielhall/status/620716996326350848 https://twitter.com/_danielhall/status/620717252216623104

While the documentation recommends using weak on properties for subviews, since iOS 6 it seems to be fine to use strong (the default ownership qualifier) instead. 尽管文档建议对子视图使用weak属性,但是从iOS 6开始,最好使用strong (默认所有权限定符)。 That's caused by the change in UIViewController that views are not unloaded anymore. 这是由于UIViewController中的更改导致不再卸载视图而引起的。

  • Before iOS 6, if you kept strong links to subviews of the controller's view around, if the view controller's main view got unloaded, those would hold onto the subviews as long as the view controller is around. 在iOS 6之前,如果您保持指向控制器视图子视图的强链接,则如果视图控制器的主视图被卸载,只要视图控制器在周围,这些视图就会保留在子视图中。
  • Since iOS 6, views are not unloaded anymore, but loaded once and then stick around as long as their controller is there. 从iOS 6开始,视图不再被卸载,而是被加载一次,然后只要它们的控制器在那里就一直存在。 So strong properties won't matter. 因此,强大的属性无关紧要。 They also won't create strong reference cycles, since they point down the strong reference graph. 它们也不会创建强参考周期,因为它们指向强参考图。

That said, I am torn between using 也就是说,我在使用之间感到恐惧

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

and

@property (nonatomic) IBOutlet UIButton *button;

in iOS 6 and after: 在iOS 6及更高版本中:

  • Using weak clearly states that the controller doesn't want ownership of the button. 明确使用weak表示控制器不希望拥有按钮。

  • But omitting weak doesn't hurt in iOS 6 without view unloading, and is shorter. 但是,在不卸载视图的情况下,忽略weak不会对iOS 6造成伤害,并且更短。 Some may point out that is also faster, but I have yet to encounter an app that is too slow because of weak IBOutlet s. 有人可能会指出这也更快,但是由于IBOutlet weak ,我还没有遇到一个太慢的应用程序。

  • Not using weak may be perceived as an error. 不使用weak可被视为错误。

Bottom line: Since iOS 6 we can't get this wrong anymore as long as we don't use view unloading. 底线:从iOS 6开始,只要我们不使用视图卸载,就不会再犯此错误。 Time to party. 参加聚会的时间。 ;) ;)

I don't see any problem with that. 我认为没有任何问题。 Pre-ARC, I've always made my IBOutlets assign , as they're already retained by their superviews. 在ARC之前,我一直将IBOutlets assign ,因为它们已被其超级视图保留。 If you make them weak , you shouldn't have to nil them out in viewDidUnload, as you point out. 如果您使它们变weak ,则不必像您指出的那样在viewDidUnload中将它们删除。

One caveat: You can support iOS 4.x in an ARC project, but if you do, you can't use weak , so you'd have to make them assign , in which case you'd still want to nil the reference in viewDidUnload to avoid a dangling pointer. 一个警告:您可以在ARC项目中支持iOS 4.x,但如果这样做,您就不能使用weak ,因此您必须将它们assign ,在这种情况下,您仍然想在其中引用无效。 viewDidUnload避免指针悬空。 Here's an example of a dangling pointer bug I've experienced: 这是我遇到的悬空指针错误的示例:

A UIViewController has a UITextField for zip code. UIViewController具有用于邮政编码的UITextField。 It uses CLLocationManager to reverse geocode the user's location and set the zip code. 它使用CLLocationManager反向对用户的位置进行地理编码并设置邮政编码。 Here's the delegate callback: 这是委托回调:

-(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];
}

I found that if I dismissed this view at the right time and didn't nil self.zip in viewDidUnload , the delegate callback could throw a bad access exception on self.zip.text. 我发现,如果我在适当的时间解雇了该视图,并且没有在viewDidUnload中将self.zip设置为nil,则委托回调可能会在self.zip.text上引发错误的访问异常。

IBOutlet should be strong, for performance reason. 出于性能原因, IBOutlet应该坚固。 See Storyboard Reference, Strong IBOutlet, Scene Dock in iOS 9 请参阅情节提要参考,Strong IBOutlet,iOS 9中的场景扩展坞

As explained in this paragraph, the outlets to subviews of the view controller's view can be weak, because these subviews are already owned by the top-level object of the nib file. 如本段所述,视图控制器视图的子视图的出口可能很弱,因为这些子视图已经由nib文件的顶级对象拥有。 However, when an Outlet is defined as a weak pointer and the pointer is set, ARC calls the runtime function: 但是,当将插座定义为弱指针并设置了指针时,ARC会调用运行时函数:

id objc_storeWeak(id *object, id value);

This adds the pointer (object) to a table using the object value as a key. 这将使用对象值作为键将指针(对象)添加到表中。 This table is referred to as the weak table. 该表称为弱表。 ARC uses this table to store all the weak pointers of your application. ARC使用此表存储应用程序的所有弱指针。 Now, when the object value is deallocated, ARC will iterate over the weak table and set the weak reference to nil. 现在,当对象值被释放时,ARC将遍历弱表并将弱引用设置为nil。 Alternatively, ARC can call: 或者,ARC可以致电:

void objc_destroyWeak(id * object)

Then, the object is unregistered and objc_destroyWeak calls again: 然后,该对象被取消注册,并且objc_destroyWeak再次调用:

objc_storeWeak(id *object, nil)

This book-keeping associated with a weak reference can take 2–3 times longer over the release of a strong reference. 与发布弱参考相关的簿记工作可能比发布强参考相关的时间长2–3倍。 So, a weak reference introduces an overhead for the runtime that you can avoid by simply defining outlets as strong. 因此,弱引用会导致运行时的开销,您只需将出口定义为强即可避免这种开销。

As of Xcode 7, it suggests strong 从Xcode 7开始,它表明功能strong

If you watch WWDC 2015 session 407 Implementing UI Designs in Interface Builder , it suggests (transcript from http://asciiwwdc.com/2015/sessions/407 ) 如果您观看WWDC 2015会议407 在Interface Builder中实现UI设计 ,则建议使用(抄本来自http://asciiwwdc.com/2015/sessions/407

And the last option I want to point out is the storage type, which can either be strong or weak. 我要指出的最后一个选项是存储类型,可以是强类型或弱类型。

In general you should make your outlet strong, especially if you are connecting an outlet to a sub view or to a constraint that's not always going to be retained by the view hierarchy. 通常,您应该使出口坚固,尤其是当您将出口连接到子视图或视图层次结构中并不总是会保留的约束时。

The only time you really need to make an outlet weak is if you have a custom view that references something back up the view hierarchy and in general that's not recommended. 真正需要弱化出口的唯一情况是,如果您有一个自定义视图,该视图引用了备份视图层次结构的内容,通常不建议这样做。

So I'm going to choose strong and I will click connect which will generate my outlet. 因此,我将选择“ strong”,然后单击“ connect”,这将生成我的插座。

In iOS development NIB loading is a little bit different from Mac development. 在iOS开发中,NIB加载与Mac开发略有不同。

In Mac development an IBOutlet is usually a weak reference: if you have a subclass of NSViewController only the top-level view will be retained and when you dealloc the controller all its subviews and outlets are freed automatically. 在Mac开发中,IBOutlet通常是一个较弱的参考:如果您有NSViewController的子类,则仅保留顶层视图,并且在取消分配控制器时,将自动释放其所有子视图和出口。

UiViewController use Key Value Coding to set the outlets using strong references. UiViewController使用键值编码使用强引用来设置出口。 So when you dealloc your UIViewController, the top view will automatically deallocated, but you must also deallocate all its outlets in the dealloc method. 因此,当您取消分配UIViewController时,顶视图将自动取消分配,但您还必须在dealloc方法中取消分配其所有出口。

In this post from the Big Nerd Ranch , they cover this topic and also explain why using a strong reference in IBOutlet is not a good choice (even if it is recommended by Apple in this case). 在Big Nerd Ranch的这篇文章中 ,他们涵盖了这个主题,并解释了为什么在IBOutlet中使用强引用不是一个好选择(即使Apple在这种情况下建议这样做)。

One thing I wish to point out here, and that is, despite what the Apple engineers have stated in their own WWDC 2015 video here: 我想在这里指出一件事,那就是,尽管苹果工程师在其自己的WWDC 2015视频中说过:

https://developer.apple.com/videos/play/wwdc2015/407/ https://developer.apple.com/videos/play/wwdc2015/407/

Apple keeps changing their mind on the subject, which tells us that there is no single right answer to this question. 苹果一直在改变主意,这告诉我们这个问题没有唯一正确的答案。 To show that even Apple engineers are split on this subject, take a look at Apple's most recent sample code, and you'll see some people use weak, and some don't. 为了表明即使是Apple工程师在这个问题上也存在分歧,请看一下Apple最新的示例代码,您会看到有些人使用弱功能,而有些人则不使用。

This Apple Pay example uses weak: https://developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-DontLinkElementID_8 这个Apple Pay示例使用了以下弱点: https : //developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-DontLinkElementID_8

As does this picture-in-picture example: https://developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayer_PlayerViewController_swift-DontLinkElementID_4 就像该画中画示例一样: https : //developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayer_PlayerViewController_swift-DontLinkElementID_4

As does the Lister example: https://developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57 和Lister示例一样: https : //developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57

As does the Core Location example: https://developer.apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift-DontLinkElementID_6 核心位置示例也是如此: https : //developer.apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift-DontLinkElementID_6

As does the view controller previewing example: https://developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift-DontLinkElementID_5 和视图控制器预览示例一样: https : //developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_Pre_Controller

As does the HomeKit example: https://developer.apple.com/library/ios/samplecode/HomeKitCatalog/Listings/HMCatalog_Homes_Action_Sets_ActionSetViewController_swift.html#//apple_ref/doc/uid/TP40015048-HMCatalog_Homes_Action_Sets_ActionSetViewController_swift-DontLinkElementID_23 就像HomeKit的例子一样: https : //developer.apple.com/library/ios/samplecode/HomeKitCatalog/Listings/HMCatalog_Homes_Action_Sets_ActionSetViewController_swift.html#//apple_ref/doc/uid/TP40015048-HMCatalog_Homes_Action_Sets_ActionSetViewController_swift-Do

All those are fully updated for iOS 9, and all use weak outlets. 所有这些都针对iOS 9进行了全面更新,并且都使用弱电插座。 From this we learn that A. The issue is not as simple as some people make it out to be. 由此我们可以了解到A.问题并不像某些人说得那么简单。 B. Apple has changed their mind repeatedly, and C. You can use whatever makes you happy :) B.苹果反复改变主意,C。您可以使用任何让自己开心的东西:)

Special thanks to Paul Hudson (author of www.hackingwithsift.com) who gave me the clarification, and references for this answer. 特别感谢Paul Hudson(www.hackingwithsift.com的作者)给了我澄清,并提供了此答案的参考。

I hope this clarifies the subject a bit better! 我希望这可以更好地阐明这个主题!

Take care. 照顾自己。

From WWDC 2015 there is a session on Implementing UI Designs in Interface Builder . 从WWDC 2015开始,有一个关于在Interface Builder中实现UI设计的会议。 Around the 32min mark he says that you always want to make your @IBOutlet strong . 他说,在32 @IBOutlet左右,您总是想使@IBOutlet 更强

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

It looks like something has changed over the years and now Apple recommends to use strong in general. 看起来这些年来已经发生了一些变化,现在苹果建议一般使用强壮的。 The evidence on their WWDC session is in session 407 - Implementing UI Designs in Interface Builder and starts at 32:30. 他们的WWDC会话的证据在会话407-在Interface Builder中实现UI设计 ,开始于32:30。 My note from what he says is (almost, if not exactly, quoting him): 他说的话我的笔记是(几乎,如果不完全是引用他的话):

  • outlet connections in general should be strong especially if we connect a subview or constraint that is not always retained by the view hierarchy 通常,出口连接应该牢固,特别是如果我们连接的子视图或约束并不总是由视图层次结构保留的话

  • weak outlet connection might be needed when creating custom views that has some reference to something back up in the view hierarchy and in general it is not recommended 创建自定义视图时,可能需要弱的插座连接,该自定义视图引用了视图层次结构中备份的内容,通常不建议这样做

In other wards it should be always strong now as long as some of our custom view doesn't create a retain cycle with some of the view up in the view hierarchy 在其他方面,只要我们的某些自定义视图没有在视图层次结构中使某些视图向上创建保留周期,它现在应该一直很强大

EDIT : 编辑:

Some may ask the question. 有些人可能会问这个问题。 Does keeping it with a strong reference doesn't create a retain cycle as the root view controller and the owning view keeps the reference to it? 用强引用保留它并不会创建保留周期,因为根视图控制器和拥有视图会保留对它的引用? Or why that changed happened? 还是为什么发生了这种变化? I think the answer is earlier in this talk when they describe how the nibs are created from the xib. 我认为答案是在本演讲的早期,当时他们描述了笔尖是如何通过xib创建的。 There is a separate nib created for a VC and for the view. 为VC和视图创建了一个单独的笔尖。 I think this might be the reason why they change the recommendations. 我认为这可能是他们更改建议的原因。 Still it would be nice to get a deeper explanation from Apple. 从苹果那里得到更深层次的解释仍然是很好的。

I think that most important information is: Elements in xib are automatically in subviews of view. 我认为最重要的信息是:xib中的元素自动出现在视图的子视图中。 Subviews is NSArray. 子视图是NSArray。 NSArray owns it's elements. NSArray拥有它的元素。 etc have strong pointers on them. 等对他们有很强的指导意义。 So in most cases you don't want to create another strong pointer (IBOutlet) 因此,在大多数情况下,您不想创建另一个强指针(IBOutlet)

And with ARC you don't need to do anything in viewDidUnload 借助ARC,您无需在viewDidUnload执行任何操作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在iOS9下,IBOutlets应该强还是弱? - Should IBOutlets be strong or weak under iOS9? IBOutlets强或弱 - 它是否真的对内存管理产生影响? (弧) - IBOutlets Strong or Weak - Does it Actually Make a Difference to Memory Management? (ARC) iOS:针对笔尖的IBOutlet的ARC强引用或弱引用(用于自定义UITableviewCell) - iOS: ARC strong or weak reference with IBOutlets for nibs (for custom UITableviewCell) 强弱IBOutlets之间的区别 - Difference between Strong and Weak IBOutlets 具有强引用和弱引用的ARC所有权 - ARC ownership with strong and weak references 在ARC下使用IBOutlet属性的用处? - Usefulness of using properties for IBOutlets under ARC? Objective-C ARC区块__strong __weak - Objective-C ARC block __strong __weak ARC关于网点和网点集合的弱引用和强引用? - ARC weak and strong references with outlets and collection of outlets? 如果我从属性中删除了强生命周期限定符,则ARC会发出警告,这不应该是因为在ARC中,强是对象类型的默认设置 - ARC gives warning if I remove strong life time qualifier from property, it should not because Under ARC, strong is the default for object types 在ARC下接收内存警告时,我应该将强大的IBOutlet设置为nil吗? - should I set strong IBOutlet to nil when receive memory warning under ARC?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM