我使用ARC专门为iOS 5开发游戏。iboutlet到UIViews(和子类)是强还是弱?

以下几点:

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

就能摆脱这一切

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

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


当前回答

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


从开发人员库总结:

From a practical perspective, in iOS and OS X outlets should be defined as declared properties. 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. 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). @property (weak) IBOutlet MyView *viewContainerSubview; @property (strong) IBOutlet MyOtherClass *topLevelObject;

其他回答

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

警告:你可以支持iOS 4。x在ARC项目中,但如果你这样做,你不能使用weak,所以你必须让它们赋值,在这种情况下,你仍然想在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];
}

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

注意,IBOutletCollection应该是@property(强,非原子)。

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

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

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

这个Apple Pay的例子使用了weak: 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完全更新的,并且都使用弱outlet。这个问题并不像有些人想的那么简单。B.苹果一再改变主意,C.你可以用任何让你高兴的东西:)

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

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

当心

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

Outlet连接通常应该是强的,特别是当我们连接的子视图或约束并不总是由 视图层次 在创建自定义视图时,可能需要弱出口连接,因为自定义视图引用了视图层次结构中的备份内容 一般来说不建议这样做

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

编辑:

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

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

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

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

在这篇来自Big Nerd Ranch的文章中,他们讨论了这个话题,并解释了为什么在IBOutlet中使用强引用不是一个好的选择(即使在这种情况下苹果推荐它)。