这是我经常看到的常见做法(包括来自一本非常流行的 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,这可能会在极少数情况下导致崩溃将一个对象存储在一个实例变量中而不保留它,而且它通常只是以错误的方式进行内存管理。

执行此操作的一种正确方法是:

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

其他提示

代码不正确。在取消分配后,您将最终发布 imgView

在您的.m文件中,您:

  1. alloc it - >你拥有它
  2. 将其添加为子视图 - >你和 UIView拥有它
  3. release it - >你不拥有它
  4. 然后在 dealloc 中,你 release imgView,尽管我们在上面的步骤3中建立了你不拥有它。当你调用 [super dealloc] 时,视图将释放它的所有子视图,我想你会得到一个例外。

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

代码不正确,您不应该在调用 dealloc 时在 init 方法中释放它(也就是说,如果您想将其保留为 ivar,则不需要,除非您需要自 addSubview 以来其他地方指向它的指针:将为您保留视图)。

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

init中的释放不正确。

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

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

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

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

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

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

基本答案是,示例代码中只应该有一个 [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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top