我一直在审查Apple文档和示例代码,以尝试确定管理IBOutlet内存的最佳方法。至少可以说,我有点困惑。
CurrentAddress示例代码将IBOutlets声明为属性:
@interface MapViewController : UIViewController <MKMapViewDelegate, MKReverseGeocoderDelegate>
{
MKMapView *mapView;
UIBarButtonItem *getAddressButton;
}
@property (nonatomic, retain) IBOutlet MKMapView *mapView;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *getAddressButton;
大。这些是在dealloc中发布的:
- (void)dealloc
{
[mapView release];
[getAddressButton release];
[super dealloc];
}
现在不应该将这些属性设置为assign?因为当设置为retain时,IBOutlet的保留计数将增加两次:一次加载nib时和另一次设置属性时?将这些属性设置为nil而不是在dealloc中释放不是更好吗?
答案 0 :(得分:7)
Apple docs说我们应该保留iOS的属性
应保留已保留的商店,并nil
和dealloc
同时viewDidUnload
。{/ p>
在Mac上,加载笔尖时,超级视图未保留的每个插座都会自动保留。 iOS的情况并非如此。这就是为什么理论上只保留视图层次结构中除视图以外的出口的原因。
Jeff LaMarche就这一主题发表了一篇非常有用的文章:Outlets, Cocoa vs. Cocoa Touch。
答案 1 :(得分:2)
一旦nib加载器完成加载所有内容并连接所有IBOutlet,它就会自动释放它加载的所有对象。如果您的IBOutlet属性声明为assign
,则下次自动释放池清空时,它指向的对象将被删除。
您可以在dealloc中将属性设置为nil而不是直接释放它们,结果是相同的。需要注意的是,如果你提供了自己的setter实现,你需要记住,你的对象的其他一些成员可能已经被释放了。
答案 2 :(得分:1)
这与MacOSX和iOS不同。在iOS中,加载视图并建立nib连接后,保留计数将为2。
这些元素中的每一个都将由视图保留一次,并由控制器保留一次。视图中的其他元素仅由视图保留。
当您的控制器释放这两个元素时,它们的保留计数会降至1。之后调用[super dealloc]。 UIViewController在其dealloc中有一个[view release],因此视图被释放(除非保留在其他地方,或之前已发布)。取消分配视图后,它会释放其子视图,并最终完全释放元素。
dealloc中首选[object release]的原因是键值编码(或您自己的代码)可能会导致在编写[self setObject:nil]时运行其他代码。这可能会导致其他对象在解除分配自身时与控制器进行交互。出于同样的原因,不应在init方法中使用setter。
刚刚发布的第二个原因。通过保留值而不将其设置为nil,我们将注意到代码在dealloc期间是否错误地访问了我们对象上的变量。这有助于捕获可能不容易追踪的错误。
答案 3 :(得分:0)
我假设你@synthesize
这些属性。如果你没有,你需要手动释放自己。你的假设非常正确,如果你在设置一个属性时继续保留,你就会泄漏内存。
让我们想一想......在我们有一个花哨的@synthesize
陈述之前,属性看起来是什么样的?
id _propertyName; // the ivar
- (id) propertyName {
return _propertyName;
}
- (void) setPropertyName:(id)v {
if (_propertyName) {
[_propertyName release]; // release the previously retained property
}
_propertyName = [v retain]; // retain this one so it doesn't fly away on us
}
现在,您不需要输入这些内容,因为@synthesize非常酷并为您生成,如果您没有指定@synchronized
的内容,它也会生成nonatomic
块,这也很漂亮。
如果您指定了assign
而不是retain
,那么您会得到类似的内容
id _propertyName; // the ivar
- (id) propertyName {
return _propertyName;
}
- (void) setPropertyName:(id)v {
_propertyName = v;
}
这是关于事物不是对象时唯一可以做的事情,因为它们只是值(有时也称为值类型,对象是引用类型)。由于无法保留值类型,因此其他类型的块没有任何意义。继续尝试用BOOL创建一个retain属性,看看LLVM或GCC告诉你去做什么;)
答案 4 :(得分:0)
不应将这些属性设置为 分配?因为当设定保留时, IBOutlet的保留计数将是 增加两倍:一次当笔尖是 加载和另一次时间 属性设置
好吧,你发布的代码是正确的。
使用时:
@property (nonatomic, retain) IBOutlet MKMapView *mapView;
你只是告诉xCode创建一个setter方法,它将创建你的MKMapView对象并在你每次调用时保留它
yourMapViewController.mapView = someMapView; // from out
// or
self.mapView = someMapView; // from in
之后mapView保留计数增加+1 并且你的MapViewController代码需要'现在你可以指向mapView并管理它......
不要担心IB nib文件...
当您使用nib加载UIViewController时,在您的情况下是类 MapViewController:UIViewController,当您发布MapViewController时,IB nib对象将会释放... 只关心你保留的对象......