6

这是我经常看到的一种常见做法(包括来自一本非常流行的 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的release是否有必要呢?

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

4

6 回答 6

9

代码不正确。你最终会imgView在它被释放后释放。

在您的 .m 文件中,您:

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

然后在 中dealloc,您releaseimgView 即使正如我们在上面的步骤 3 中建立的那样,您并不拥有它。当您调用[super dealloc]时,视图将释放其所有子视图,我想您会遇到异常。

如果您想保留 ivar imgView,我建议您在将其添加为子视图后不要调用,并保持不变。这样,即使在某个点从视图层次结构中删除,您仍然可以对它进行有效引用。releasedeallocimgView

于 2009-05-05T02:13:38.977 回答
0

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

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

于 2009-05-05T02:24:57.047 回答
0

初始化中的释放不正确。

您提到了“常见做法”和一本未命名的书。我建议查看 Apple 的规范示例:ViewTransitions 是这种情况的一个很好的示例(以及 2 个要启动的视图;)

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

于 2009-05-05T02:39:09.510 回答
0

[imgView release]基本答案是,示例代码中应该只有一个(无论是在 addSubview 之后还是在 dealloc 中)。但是,我会[imgView release]在.deallocaddSubview

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

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

在此示例中,如果给定的代码块是易失性的并且有机会再次执行(无论是因为内存还是未加载的视图),我[imgView release];将从 dealloc 中删除并在 addSubView 之后将其保留。

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

于 2009-05-05T12:39:59.893 回答
0

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

@bentford:如果我错了,请纠正我,但我相信为了使用 imgView 属性的综合设置器,您必须使用“self.imgView”:

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

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

于 2009-05-15T02:33:30.287 回答
-1

是的,该代码有问题。它过早释放 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];
}
于 2009-05-14T03:20:29.387 回答