10

我一直在查看 Apple 文档和示例代码,试图确定管理 IBOutlets 内存的最佳方式。我有点困惑,至少可以这么说。

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

现在不应该将这些属性设置为分配吗?因为当设置为retain时,IBOutlet的retain count会增加两次:一次是加载nib的时候,另一次是设置属性的时候?将这些属性设置为 nil 而不是在 dealloc 中释放不是更好吗?

4

5 回答 5

7

Apple 文档说我们应该保留 iOS 的属性。
保留的出口应在 和 中释放和nil编辑。deallocviewDidUnload

在 Mac 上,在加载 nib 时会自动保留每个未由 superview 保留的 outlet。iOS 并非如此。这就是为什么在视图层次结构中只保留视图以外的出口在理论上是有效的。

Jeff LaMarche 关于这个主题有一篇非常有用的帖子:Outlets, Cocoa vs. Cocoa Touch

于 2011-03-08T13:29:32.677 回答
2

一旦 nib 加载器完成加载所有内容并连接所有 IBOutlets,它会自动释放它加载的所有对象。如果您的 IBOutlet 属性被声明为assign,那么它指向的对象将在下次自动释放池清空时被删除。

可以在dealloc中将属性设置为nil,而不是直接释放,结果是一样的。需要注意的是,如果您提供了自己的 setter 实现,则需要记住对象的其他一些成员可能已经被释放。

于 2011-03-08T13:30:40.873 回答
1

这对于 MacOSX 和 iOS 是不同的。在 iOS 中,在加载视图并建立 nib 连接后,保留计数将为 2。

这些元素中的每一个都将由视图保留一次,由您的控制器保留一次。视图中的其他元素将仅由视图保留。

当您的控制器释放这两个元素时,它们的保留计数会减少到 1。之后调用 [super dealloc]。UIViewController 在它的dealloc中有一个[view release],所以这个view被释放了(除非保留在别处,或者之前被释放)。当视图被释放时,它释放它的子视图,元素最终被完全释放。

在 dealloc 中首选 [object release] 的原因是键值编码(或您自己的代码)可能会导致在您编写 [self setObject:nil] 时运行额外的代码。这可能会导致其他对象在释放自身时与您的控制器进行交互。出于同样的原因,不应在 init 方法中使用设置器。

仅仅做释放还有第二个原因。通过保留该值而不将其设置为 nil,我们会注意到代码是否在稍后在 dealloc 期间错误地访问了我们对象上的该变量。这可以帮助捕获可能不容易追踪的错误。

于 2011-03-08T13:39:30.243 回答
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如果您不指定某些东西作为 being nonatomic,它也会生成块,这也很不错。

如果你指定assign而不是retain,你会得到这样的东西

id _propertyName; // the ivar

- (id) propertyName {
  return _propertyName;
}

- (void) setPropertyName:(id)v {
  _propertyName = v;
}

当事物不是对象时,这是您唯一可以做的事情,因为它们只是值(有时也称为值类型,对象是引用类型)。由于无法保留值类型,因此其他类型的块没有任何意义。继续尝试使用 BOOL 创建一个保留属性,并观察 LLVM 或 GCC 告诉你做什么;)

于 2011-03-08T13:40:40.497 回答
0

不应该将这些属性设置为分配吗?因为当设置为retain时,IBOutlet的retain count会增加两次:一次是加载nib的时候,另一次是设置属性的时候

好吧,您发布的代码是正确的。

当你使用:

@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 加载 UIViewController 时,在您的情况下是 MapViewController 类:UIViewController,当您释放 MapViewController 时,IB nib 对象将释放...只需关心您保留的对象...

于 2011-03-08T13:41:13.663 回答