如果IBOutlets在ARC下是强还是弱?

时间:2011-10-06 17:56:36

标签: ios objective-c cocoa-touch interface-builder automatic-ref-counting

我使用ARC专门为iOS 5开发。 IBOutletUIView s(和子类)的strong应该是weak还是@property (nonatomic, weak) IBOutlet UIButton *button;

以下内容:

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

将摆脱所有这些:

strong

这样做有什么问题吗?模板使用UIViewController,因为直接从“Interface Builder”编辑器连接到标题时创建的自动生成属性,但为什么? strong已对view的{​​{1}}引用保留其子视图。

11 个答案:

答案 0 :(得分:448)

警告,答案:根据WWDC 2015,此答案不是最新的,正确答案请参阅上面的accepted answer(Daniel Hall)。这个答案将留作记录。


摘自developer library

  

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

     
      
  • 您创建的出口,例如视图控制器视图或窗口控制器窗口的子视图,是不暗示所有权的对象之间的任意引用。

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

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

答案 1 :(得分:224)

Apple目前推荐的最佳做法是让IBOutlets ,除非特别需要 weak 以避免保留周期。正如Johannes上面提到的,在WWDC 2015的“实现界面生成器中的UI设计”会话中对此进行了评论,Apple工程师说:

  

我想指出的最后一个选项是存储类型,可以   无论是强者还是弱者。一般来说,你应该做出自己的出路   强大,特别是如果您将插座连接到子视图或   视图并不总是保留的约束   层次结构。你真正需要做出一个弱点的唯一一次是if   你有一个自定义视图,引用备份视图的东西   层次结构,一般不推荐。

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

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

答案 2 :(得分:48)

虽然文档建议在子视图的属性上使用weak,但是从iOS 6开始,使用strong(默认的所有权限定符)似乎没问题。这是由于通过UIViewController中的更改,视图不再被卸载。

  • 在iOS 6之前,如果您保持与控制器视图的子视图的强大链接,如果视图控制器的主视图被卸载,只要视图控制器在周围,那些视图就会保留在子视图中。
  • 从iOS 6开始,视图不再被卸载,但只需加载一次,然后只要控制器在那里就可以停留。如此强大的属性无关紧要。他们也不会创建强大的参考周期,因为他们指出了强大的参考图。

那就是说,我在使用

之间挣扎
@property (nonatomic, weak) IBOutlet UIButton *button;

@property (nonatomic) IBOutlet UIButton *button;

在iOS 6及之后:

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

  • 但是在没有视图卸载的情况下省略weak在iOS 6中没有受到伤害,而且更短。有些人可能会指出也更快,但由于weak IBOutlet s,我还没有遇到过慢的应用。

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

结论:从iOS 6开始,只要我们不使用视图卸载,我们就不会再出错了。聚会的时间。 ;)

答案 3 :(得分:34)

我没有看到任何问题。在ARC之前,我总是制作我的IBOutlets assign,因为他们的超级视图已经保留了它们。如果你制作它们weak,你应该不必在viewDidUnload中将它们取出,正如你所指出的那样。

一个警告:您可以在ARC项目中支持iOS 4.x,但如果这样做,则无法使用weak,因此您必须使用assign,其中你仍然希望在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];
}

我发现如果我在正确的时间解散了这个视图并且没有在viewDidUnload中使用self.zip,则委托回调可能会在self.zip.text上抛出一个错误的访问异常。

答案 4 :(得分:20)

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

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

UiViewController使用键值编码来使用强引用设置出口。因此,当您释放UIViewController时,顶视图将自动解除分配,但您还必须在dealloc方法中释放其所有出口。

In this post from the Big Nerd Ranch,它们涵盖了这个主题,并解释了为什么在IBOutlet中使用强引用不是一个好的选择(即使在这种情况下Apple推荐它)。

答案 5 :(得分:20)

出于性能原因,

sudo service nginx restart应该很强大。见Storyboard Reference, Strong IBOutlet, Scene Dock in iOS 9

  

如本段所述,视图子视图的出口   控制器的视图可能很弱,因为这些子视图已经存在   由nib文件的顶级对象拥有。但是,当一个奥特莱斯   被定义为弱指针并且指针被设置,ARC调用   运行时功能:

     

IBOutlet

     

这会添加指针   (对象)使用对象值作为键的表。这张桌子是   被称为弱表。 ARC使用此表存储所有   你的应用程序的弱指针。现在,当对象值是   取消分配后,ARC将遍历弱表并设置弱点   参考零。或者,ARC可以致电:

     

id objc_storeWeak(id *object, id value);

     

然后,对象是   unregistered和objc_destroyWeak再次调用:

     

void objc_destroyWeak(id * object)

     

这本书保持联系   弱引用可能比释放a长2-3倍   强烈的参考。因此,弱引用引入了开销   通过简单地将出口定义为强大而可以避免的运行时。

从Xcode 7开始,它建议objc_storeWeak(id *object, nil)

如果你观看WWDC 2015会话407 Implementing UI Designs in Interface Builder,它建议(来自http://asciiwwdc.com/2015/sessions/407的成绩单)

  

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

     

一般情况下,您应该使您的插座强大,特别是如果您将插座连接到子视图或视图层次结构并不总是保留的约束。

     

你唯一真正需要让出口变弱的一个方法就是如果你有一个自定义视图引用视图层次结构中的某些内容,而且通常不推荐这样做。

     

所以我要选择强力,我会点击连接,这将产生我的插座。

答案 6 :(得分:15)

我想在此指出一点,那就是,尽管Apple工程师在他们自己的WWDC 2015视频中已经说明了这一点:

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

Apple不断改变主题,这告诉我们这个问题没有一个正确答案。为了表明即使苹果公司的工程师在这个问题上存在分歧,请看看Apple的最新版本 示例代码,您会看到有些人使用弱,而有些人不会。

此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

这个画中画示例如下: https://developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayer_PlayerViewController_swift-DontLinkElementID_4

Lister示例如下: https://developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57

核心位置示例也是如此: 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/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift-DontLinkElementID_5

与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-DontLinkElementID_23

所有这些都针对iOS 9进行了全面更新,并且都使用弱插座。由此我们了解到A.问题并不像有些人想象的那么简单。 B. Apple反复改变主意,C。你可以使用任何让你开心的事情:)

特别感谢Paul Hudson(www.hackingwithsift.com的作者)给我的澄清,以及对此答案的参考。

我希望这能更好地澄清这个主题!

小心。

答案 7 :(得分:9)

来自WWDC 2015的Implementing UI Designs in Interface Builder会话。在32分钟左右,他说你总是希望让你的@IBOutlet 强大

答案 8 :(得分:6)

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

答案 9 :(得分:5)

多年来似乎发生了一些变化,现在Apple建议使用强大的功能。 WWDC会议的证据在session 407 - Implementing UI Designs in Interface Builder,从32:30开始。我所说的是(几乎,如果不完全是,引用他):

  • 出口连接一般应该很强,特别是如果我们连接的子视图或约束并不总是由 查看层次结构

  • 创建自定义视图时可能需要弱插座连接,该视图对视图层次结构中备份的内容有一些参考 一般情况下不推荐

在其他病房中,只要我们的某些自定义视图没有在视图层次结构中创建一些视图的保留周期,它就应该总是很强大

编辑:

有些人可能会问这个问题。使用强引用保留它不会创建保留周期,因为根视图控制器和拥有视图会保留对它的引用吗?或者为什么发生了变化? 我认为当他们描述如何从xib创建笔尖时,答案在本次演讲中更早。为VC和视图创建了一个单独的nib。我认为这可能是他们改变建议的原因。从Apple那里得到更深入的解释仍然会很好。

答案 10 :(得分:4)

我认为最重要的信息是: xib中的元素自动位于视图的子视图中。子视图是NSArray。 NSArray拥有它的元素。等等有强烈的指针。所以在大多数情况下你不想创建另一个强指针(IBOutlet)

使用ARC,您无需在viewDidUnload

中执行任何操作