3

我目前正在研究 Apress 的“开始 iPhone 3 开发”。他们在示例应用程序中使用的标准类似于以下代码:

- (void)viewDidLoad {
    BlueViewController *blueController = [[BlueViewController alloc] 
                                         initWithNibName:@"BlueView" bundle:nil];
    self.blueViewController = blueController;
    [self.view insertSubview:blueController.view atIndex:0];
    [blueController release];
}

8.14.11 UPDATE(附加信息)
blueViewController 声明如下:

@property (retain, nonatomic) BlueViewController *blueViewController;

每当他们执行时,alloc他们将其放入某个临时变量(此处blueController)中,然后分配它,然后释放它。这个临时变量对我来说似乎是多余的。
我将代码简化如下:

- (void)viewDidLoad {
    self.blueViewController = [[BlueViewController alloc] 
                              initWithNibName:@"BlueView" bundle:nil];
    [self.view insertSubview:blueViewController.view atIndex:0];
}

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

我修改后的代码在 iPhone 模拟器中运行相同。现在,我知道了如果你分配了一些东西就需要释放它的规则。我在我的dealloc方法中涵盖了这一点。但是直接在(被调用ViewDidLoad的函数)中发布有什么好处吗?alloc或者release在你的dealloc方法中有这样的方法同样可以吗?
感谢您的帮助,
-j

4

3 回答 3

8

假设blueViewController是一个retain属性,临时变量不是多余的。您的简化正在造成内存泄漏。第二个片段中的此语句泄漏:

self.blueViewController = [[BlueViewController alloc] 
                          initWithNibName:@"BlueView" bundle:nil];

在所有权方面,您拥有 alloc-init 返回的对象,然后属性访问器再次声明该对象的所有权,导致该对象被过度保留

使用临时变量可以解决这个问题。另一种选择是使用autorelease

self.blueViewController = [[[BlueViewController alloc] 
                          initWithNibName:@"BlueView" bundle:nil] autorelease];

请注意,在此语句之后,您实际上拥有该对象,并且您必须在 dealloc 中释放它。


您没有提到该属性blueViewController是如何声明的。无论如何,无论 setter 的语义是什么 ( retain, copy, assign),该语句都是错误的。我已经解释了最可能的情况:retain. 让我们看看其他两种可能性(不考虑它们是否有意义):

  • 如果blueViewController碰巧是一个copy属性,该语句也会泄漏。属性访问器复制原始对象,现在该属性包含一个指向副本的指针,您丢失了原始对象的跟踪,立即泄漏它。

  • 最不可能的情况是这blueViewController是一个assign属性,因为这很可能是错误的并且您确实想要retain。但是,无论如何,这些assign属性适用于您不拥有的对象,例如委托,并且您不应该释放它们。您正在将您拥有的对象分配给它,因此要么泄漏它,要么错误地释放了 assign 属性。

于 2011-08-12T15:35:12.263 回答
3
@property (retain) MyCLass *obj;

MyClass *tmpObj = [[MyClass alloc] init];
self.obj = tmpObj;
[tmpObj release];

在第一行中,您可以通过alloc. 然后在第二行,您再次获得所有权,因为该财产被保留。在第 3 行中,您释放通过alloc. 现在您通过保留属性拥有单一所有权,您将来可能会释放它,可能位于dealloc.

现在考虑如果删除tmpObj.

self.obj = [[MyClass alloc] init];

在这一行中,您获得两次所有权,一次alloc通过财产,一次通过财产。现在[obj release]一次是不够的。您需要释放它两次以避免泄漏,自然释放两次是非常糟糕的,并且可能是进一步内存泄漏的来源。如果您再次拨打电话,self.obj = anotherObj那么您正在泄漏旧电话。为避免这种情况,您需要此临时指针。

于 2011-08-12T15:38:04.403 回答
0

我能想到的原因有两个;第一个,更具体的例子是,你经常会看到类似的方法blueController被分配和初始化,然后在实际分配给selfivar 之前测试有效性。在每个此类方法中遵循此模式将使您更容易在创建对象和分配它之间进行测试,如果您意识到需要发生这种情况。据我所知,如果这样的中介确实是多余的,编译器应该优化它。

Cocoa 中这种模式的第二个更通用的目的是 Obj-C 和 Cocoa 鼓励方法和变量使用极长、冗长的名称,因此单个方法调用最终可能跨越多行;使用方法调用作为其他方法的直接参数很快就会变得不可读,因此约定鼓励提前为方法设置每个参数,将它们放在中间变量中,然后将变量用作参数以增强可读性,并使其更容易更改一个参数,而不必挖掘嵌套的方法调用。

于 2011-08-12T15:34:04.283 回答