简体   繁体   English

iOS - 管理IBOutlets内存的最佳方法是什么?

[英]iOS - What is best way to manage memory for IBOutlets?

I've been reviewing the Apple docs and sample code to try to determine the best way to manage memory for IBOutlets. 我一直在审查Apple文档和示例代码,以尝试确定管理IBOutlet内存的最佳方法。 I'm a little confused, to say the least. 至少可以说,我有点困惑。

The CurrentAddress sample code declares IBOutlets as properties: CurrentAddress示例代码将IBOutlets声明为属性:

@interface MapViewController : UIViewController <MKMapViewDelegate, MKReverseGeocoderDelegate>

{
    MKMapView *mapView;
    UIBarButtonItem *getAddressButton;
}
@property (nonatomic, retain) IBOutlet MKMapView *mapView;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *getAddressButton;

Great. 大。 And these are released in dealloc: 这些是在dealloc中发布的:

- (void)dealloc
{
    [mapView release];
    [getAddressButton release];
    [super dealloc];
}

Now shouldn't these properties be set to assign? 现在不应该将这些属性设置为分配? Because when set to retain, the IBOutlet's retain count will be increased twice: once when the nib is loaded and another time when the property is set? 因为当设置为retain时,IBOutlet的保留计数将增加两次:一次加载nib时和另一次设置属性时? And wouldn't it be better to set these properties to nil instead of releasing in dealloc? 将这些属性设置为nil而不是在dealloc中释放不是更好吗?

Apple docs says we should retain properties for iOS. Apple文档说我们应该保留iOS的属性。
Retained outlets should be released and nil 'ed in both dealloc and viewDidUnload . 留存网点应该被释放和nil “编在这两个deallocviewDidUnload

On the Mac, every outlet which is not retained by a superview is automatically retained when loading the nib. 在Mac上,加载笔尖时,每个未由superview保留的插座会自动保留。 That's not the case with iOS. iOS的情况并非如此。 That's why it's theoretically valid to only retain outlets other than views in the view hierarchy. 这就是为什么理论上只保留视图层次结构中视图以外的出口的原因。

There's a very helpful post by Jeff LaMarche regarding this topic: Outlets, Cocoa vs. Cocoa Touch . Jeff LaMarche就这一主题发表了一篇非常有用的文章: Outlets,Cocoa vs. Cocoa Touch

Once the nib loader finishes loading everything and connecting all the IBOutlets, it autoreleases all the objects it loaded. 一旦nib加载器完成加载所有内容并连接所有IBOutlet,它就会自动释放它加载的所有对象。 If your IBOutlet property was declared as assign , then the object it points to would be deleted next time the autorelease pool emptied. 如果您的IBOutlet属性声明为assign ,则下次自动释放池清空时,它指向的对象将被删除。

You can set the properties to nil in dealloc instead of directly releasing them, the result is the same. 您可以在dealloc中将属性设置为nil而不是直接释放它们,结果是相同的。 The thing to watch for is, if you've provided your own implementation of the setter, you need to keep in mind that some of the other members of your object may already have been released. 需要注意的是,如果您提供了自己的setter实现,则需要记住,对象的某些其他成员可能已经被释放。

This is different for MacOSX and iOS. 这与MacOSX和iOS不同。 In iOS the retain count will be two after the view is loaded and the nib connections are established. 在iOS中,加载视图并建立nib连接后,保留计数将为2。

Each of these elements will be retained once by the view and once by your controller. 这些元素中的每一个都将由视图保留一次,并由控制器保留一次。 Additional elements in the view will be retained only by the view only. 视图中的其他元素仅由视图保留。

When your controller releases the two elements, their retain count goes down to one. 当您的控制器释放这两个元素时,它们的保留计数会降至1。 After that [super dealloc] is called. 之后调用[super dealloc]。 UIViewController has a [view release] in its dealloc, so the view is released (unless retained elsewhere, or previously released). UIViewController在其dealloc中有一个[view release],因此视图被释放(除非保留在其他地方,或之前已发布)。 When the view is deallocated, it releases its sub views, and the elements are finally completely freed. 取消分配视图时,它会释放其子视图,并最终完全释放元素。

The reason why [object release] is preferred in dealloc, is that key-value coding (or your own code) might cause additional code to be run when you write [self setObject:nil]. dealloc中首选[object release]的原因是键值编码(或您自己的代码)可能会导致在编写[self setObject:nil]时运行其他代码。 This can potentially cause other objects to interact with your controller when it is in the middle of deallocating itself. 这可能会导致其他对象在解除分配自身时与控制器进行交互。 Setters should not be used in the init method for the same reason. 出于同样的原因,不应在init方法中使用setter。

There is a second reason for just doing release. 刚刚发布的第二个原因。 By leaving the value and not setting it to nil, we'll notice if code erroneously access that variable on our object later during dealloc. 通过保留值而不将其设置为nil,我们将注意到代码在dealloc期间是否错误地访问了我们对象上的变量。 This can help catch bugs that might not be easy to track down otherwise. 这可以帮助捕获可能不容易追踪的错误。

I'm assuming you @synthesize these properties. 我假设你@synthesize这些属性。 If you didn't, you would need to release yourself manually. 如果你没有,你需要手动释放自己。 You are very correct in your assumption that if you continued to retain when a property is set, you would leak memory. 你的假设非常正确,如果你在设置一个属性时继续保留,你就会泄漏内存。

Let's think.... what did properties used to look like before we had the fancy @synthesize statement? 让我们想一想......在我们拥有花哨的@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
}

Now, you don't need to type this stuff, because @synthesize is cool and generates that for you, it will also generate @synchronized blocks if you do not specify something as being nonatomic , which is also pretty rad. 现在,你不需要输入这些东西,因为@synthesize很酷并为你生成,如果你没有指定nonatomic东西,它也会产生@synchronized块,这也是非常好的。

If you specified assign instead of retain , you'd get something like this 如果您指定了assign而不是retain ,那么您将获得类似的结果

id _propertyName; // the ivar

- (id) propertyName {
  return _propertyName;
}

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

This is about the only thing you CAN do when things are not objects, because they are only values (also sometimes referred to as value types, objects are reference types). 当事物不是对象时,这是你唯一可以做的事情,因为它们只是值(有时也称为值类型,对象是引用类型)。 Since value types cannot be retained, the other type of block wouldn't make any sense. 由于无法保留值类型,因此其他类型的块没有任何意义。 Go ahead and try to create a retain property with BOOL and watch what LLVM or GCC tell you to go do with what ;) 继续尝试用BOOL创建一个retain属性,看看LLVM或GCC告诉你去做什么;)

shouldn't these properties be set to assign? 不应该将这些属性设置为分配? Because when set to retain, the IBOutlet's retain count will be increased twice: once when the nib is loaded and another time when the property is set 因为当设置为retain时,IBOutlet的保留计数将增加两次:一次加载nib时和另一次设置属性时

well, the code you posted is right as it is. 好吧,你发布的代码是正确的。

when you use: 当你使用:

@property (nonatomic, retain) IBOutlet MKMapView *mapView;

you are just telling xCode to create a setter method which will create your MKMapView object and retain it everytime you call 你只是告诉xCode创建一个setter方法,它将创建你的MKMapView对象,并在你每次调用时保留它

yourMapViewController.mapView = someMapView; // from out

// or

self.mapView = someMapView; // from in

after that mapView retain count increase +1 and your MapViewController code need that 'couse now you can point to mapView and manage it... 之后mapView保留计数增加+1并且你的MapViewController代码需要'现在你可以指向mapView并管理它...

don't worry for the IB nib file... 不要担心IB nib文件...

when you load a UIViewController with a nib, in your case the class MapViewController : UIViewController, the IB nib objects will release when you release your MapViewController... just care of the objectS you retain... 当您使用nib加载UIViewController时,在您的情况下使用类MapViewController:UIViewController,当您释放MapViewController时,IB nib对象将释放...只关心您保留的对象...

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM