繁体   English   中英

iPhone内存管理和发布

[英]iPhone Memory Management and Releasing

这是我经常看到的常见做法(包括来自非常受欢迎的iPhone开发者书)

在.h文件中:

@interface SomeViewController : UIViewController
{
  UIImageView *imgView;
}

在.m文件中的某个地方:

imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
applicationFrame]];
[imgView setImage:[UIImage imageNamed:@"someimage.png"]];
[self addSubview:imgView];
[imgView release];

后来,我们看到了......

- (void) dealloc
{
  [imgView release];
  [super dealloc];

} 

由于imgView具有匹配的alloc和release,是否需要在dealloc中发布imgView?

addSubview调用保留的imgView在哪里占了?

代码不正确。 在解除分配后,你最终会发布imgView

在.m文件中,您:

  1. alloc它 - >你拥有它
  2. 将其添加为子视图 - >您和UIView拥有它
  3. release它 - >你不拥有它

然后在deallocrelease imgView,即使我们在上面的步骤3中建立了你不拥有它。 当你调用[super dealloc] ,视图将释放它的所有子视图,我想你会得到一个例外。

如果你想保留imgView的ivar,我建议你在将它添加为子视图后不要调用release ,并保持你的dealloc相同。 这样,即使imgView在某个时候从视图层次结构中删除,您仍然会有一个有效的引用。

代码是不正确的,你不应该在init方法中释放它,就像调用dealloc一样(如果你想把它保存为ivar,你不需要除非你需​​要指向它的其他地方,因为addSubview :将为您保留视图)。

我相信它实际上没有崩溃的原因是因为它仍然被超类保留(从调用addSubview :),所以当它在dealloc中发布时实际上是平衡的。 该视图可能会在[super dealloc]视图后立即将其自身从[super dealloc]视图中删除,因此当调用[super dealloc] ,它不会被过度释放。 这是我的预感,至少。

init中的释放不正确。

你提到了“普通的做法”和一本未命名的书。 我建议查看Apple的规范示例:ViewTransitions就是这种情况的一个很好的例子(并且有2个视图可以启动;)

http://developer.apple.com/iphone/library/samplecode/ViewTransitions/index.html

基本答案是,示例代码中应该只有一个[imgView release]无论是在addSubview之后还是在dealloc中 )。 但是,我会从dealloc删除[imgView release]并在addSubview之后保留它。

iPhone上有一个问题; 使用didReceiveMemoryWarning ,您可以从您下面释放对象( 包括整个视图 )。 如果您有一个应用程序范围的保留集并且您不尊重内存,那么您可能会发现该应用程序只是被杀死了。

一个很好的例子是:
如果你想到一组嵌套的3个视图,请查看1->视图2->视图3.接下来,考虑' viewDidLoad '和' viewDidUnload '调用。 如果用户当前处于“视图3”中,则可能会卸载View1,这就是令人讨厌的地方。
如果在viewDidLoad分配了一个对象,并且在将其添加到子视图后没有释放它,则在卸载view1时不会释放您的对象,但仍然会卸载view1。
viewDidLoad将再次运行,您的代码将再次运行,但现在您已经有两个对象实例化而不是一个; 一个对象将在以前卸载的视图中处于无处,并且新对象将用于当前可见的视图。 冲洗,起泡和重复,您会发现应用程序因内存泄漏而崩溃。

在这个例子中,如果给定的代码块是易失性的并且有机会再次执行( 无论是因为内存还是卸载的视图 ),我会删除[imgView release]; 来自dealloc并在addSubView之后保留它。

以下是基本保留/释放概念的链接: http//www.otierney.net/objective-c.html#retain

(我没有足够的声誉来添加评论 。)

@bentford:如果我错了,请纠正我,但我相信为了使用imgView属性的合成setter,你必须使用“self.imgView”:

self.imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]

如果你没有自我。 ,它只是使用了ivar,并没有得到额外的保留。

是的,该代码存在问题。 过早地释放imgView,这可能会在极少数情况下导致崩溃 而不保留实例变量中的对象,而且通常只是以错误的方式进行内存管理。

一个正确的方法是:

@interface SomeViewController : UIViewController
{
    UIImageView *imgView;
}
@property (nonatomic, retain) UIImageView *imgView;

并在实施中;

@synthesize imgView;

模块中的某个地方:

//Create a new image view object and store it in a local variable (retain count 1)
UIImageView *newImgView = [[UIImageView alloc] initWithFrame:self.view.bounds];
newImgView.image = [UIImage imageNamed:@"someimage.png"];

//Use our property to store our new image view as an instance variable,
//if an old value of imgView exists, it will be released by generated method,
//and our newImgView gets retained (retain count 2)
self.imgView = newImgView;

//Release local variable, since the new UIImageView is safely stored in the
//imgView instance variable. (retain count 1)
[newImgView release];

//Add the new imgView to main view, it's retain count will be incremented,
//and the UIImageView will remain in memory until it is released by both the
//main view and this controller. (retain count 2)
[self.view addSubview:self.imgView];

而dealloc仍然是相同的:

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

暂无
暂无

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

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