目标C:为什么在创建ui对象后立即释放

时间:2009-09-06 19:55:33

标签: iphone objective-c cocoa-touch

许多iPhone代码示例(来自Apple等)都包含以下代码:

- (void)viewDidLoad {
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];

// add the top-most parent view
UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame];
contentView.backgroundColor = [UIColor blackColor];
self.view = contentView;
[contentView release];

levelView = [[LevelView alloc] initWithFrame:applicationFrame viewController:self];
[self.view addSubview:levelView];

calibrationView = [[CalibrationView alloc] initWithFrame:applicationFrame viewController:self];
}

此片段来自BubbleLevel示例项目。

我的问题:为什么发布消息发送到contentView?我们在self.view中保留对contentView的引用,我们显然希望在应用程序的生命周期中使用它,而不仅仅是在此方法中。不会调用release会导致视图被释放吗?

4 个答案:

答案 0 :(得分:13)

Ölbaum说self.view = contentView;将保留您的观点是正确的,这意味着它不会被取消分配。但是,这种情况并非总是如此:

如果您查看UIViewController的文档(或标题),您会看到view属性声明如下:

@property(nonatomic, retain) UIView *view;

这意味着只要设置了视图属性(foo.view = anotherView[foo setView:anotherView];),就会保留其他视图。如果view属性声明为:

@property(nonatomic, assign) UIView *view;

然后视图将保留。它会将一个简单的指针指定到实例变量中。在这种情况下,您认为后续的releasecontentView会破坏视图是正确的,这意味着控制器会有一个陈旧的指针,这意味着您的应用可能会崩溃。

换句话说,当您使用属性时,请确保知道它们是retain还是assign。 (如果没有说,那就是assign)。然后相应地处理你的内存管理。

答案 1 :(得分:8)

不,因为self.view = contentView会保留它。由于您必须平衡保留和释放呼叫,因此您需要释放它以平衡分配。

答案 2 :(得分:6)

不要认为retain / release只是为了平衡。他们所做的是转让所有权。理解所有权的概念,并了解Cocoa中的内存管理。

所有权在范围内设定;方法范围,对象实例范围或全局应用程序范围。方法拥有通过保留局部变量。对象实例拥有具有保留的实例变量。并且应用程序拥有,具有保留的全局变量。

如果您从名为alloc的方法调用中收到该对象,或者包含单词new或copy (如newSprocketmutableCopy中所述),则当前方法拥有该对象< / em>的。通过其他方式提供给您的所有对象都不归您所有,例如方法的参数或大多数方法调用的结果。

您可以访问您不拥有的对象实例,您可以一直这样做。如果您希望对象实例超过当前方法的执行(或者如果您想要挑剔地运行循环),则只需要明确取得retain的所有权。

这行代码取得了从局部变量contentView引用的对象实例的所有权。方法loadView现在拥有该对象。

UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame];

接下来,对象实例self获取所有权,因为该属性被声明为保留。对象实例现在有两个所有者,包括方法和类。

self.view = contentView;

从此开始,我们永远不会通过此方法中的局部变量访问视图对象。该方法不再需要它,因此重新拥有它。现在,该对象仅由对象实例拥有,并且不再是此方法的问题

[contentView release];

答案 3 :(得分:5)

如果你已经习惯了其他语言,可能很自然地看self.view = contentView并想一想,“哦,它正在分配一个实例变量。”但它不是 - 实例变量不能用点分配,因为Objective-C中的对象总是指针。这是一个属性访问者。在大多数情况下,它完全等同于编写[self setView:contentView]

在大多数情况下,setter方法将实现如下:

- (void)setView:(UIView *)view {
    if (view != _view) {
        [_view release]; // where _view is the name of the actual instance variable
        _view = [view retain];
    }
}

在这种情况下,设置属性时会保留它。所以你必须在那里发布它,否则分配对象造成的初始所有权永远不会被释放。