这是我经常看到的一种常见做法(包括来自非常受欢迎的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在哪里占了?
答案 0 :(得分:9)
代码不正确。在解除分配后,您最终会发布imgView
。
在您的.m文件中,您:
alloc
它 - >你拥有它release
它 - >你不拥有它然后在dealloc
中,您release
imgView即使我们在上面的步骤3中建立了您不拥有它。当您致电[super dealloc]
时,视图会释放所有子视图,我想您会遇到异常。
如果您想保留imgView
的ivar,我建议不在您将其添加为子视图后调用release
,并保留dealloc
相同。这样,即使imgView
在某个时候从视图层次结构中删除,您仍然会有一个有效的引用。
答案 1 :(得分:0)
代码不正确,你不应该在init方法中释放它,就像调用dealloc一样(如果你想把它保存为ivar,你不需要除非你需要一个指向它的指针)其他地方,因为addSubview:将为你保留视图)。
我相信它实际上没有崩溃的原因是因为它仍然被超类(从调用addSubview :)保留,所以当它在dealloc中发布时实际上是平衡的。该视图可能会在超级视图后立即从超级视图中删除,因此当调用[super dealloc]
时,它不会被过度释放。这是我的预感,至少。
答案 2 :(得分:0)
init中的释放不正确。
你提到了“普通的做法”和一本未命名的书。我建议查看Apple的规范示例:ViewTransitions就是这种情况的一个很好的例子(并且有2个视图可以启动;)
http://developer.apple.com/iphone/library/samplecode/ViewTransitions/index.html
答案 3 :(得分:0)
基本答案是,示例代码中只应该有一个[imgView release]
(是在addSubview之后还是在dealloc 之后)。不过,我会从[imgView release]
中移除dealloc
,然后将其留在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
答案 4 :(得分:0)
(我没有足够的声誉来添加评论。)
@bentford:如果我错了,请纠正我,但我相信为了使用imgView属性的合成setter,你必须使用“self.imgView”:
self.imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
如果你没有 self。,它只是使用了ivar,并没有得到额外的保留。
答案 5 :(得分:-1)
是的,该代码存在问题。它
执行此操作的一种正确方法是:
@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];
}