为什么iPhone示例代码使用了这么多中间变量?

时间:2011-08-12 15:25:35

标签: objective-c ios memory-management simplification

我目前正在研究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更新(附加信息)
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

3 个答案:

答案 0 :(得分:8)

假设blueViewControllerretain属性,临时变量不是多余的。您的简化会造成内存泄漏。来自第二个片段的声明泄漏:

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

就所有权而言,您拥有alloc-init返回的对象,然后属性访问者再次声明对象的所有权,从而导致对象过度保留

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

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

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


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

  • 如果blueViewController恰好是copy属性,则该语句也会泄漏。属性访问器复制原始对象,现在该属性包含指向副本的指针,并且您丢失了原始对象的跟踪,并立即将其泄漏。

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

答案 1 :(得分:3)

@property (retain) MyCLass *obj;

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

在第一行中,您通过alloc获得一次所有权。然后在第二行,您将获得所有权,因为该属性被保留。在第3行,您将通过alloc释放您拥有的所有权。现在,您通过retain属性拥有一个所有权,您将来可能会发布该属性,可能位于dealloc

现在考虑如果删除tmpObj会发生什么。

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

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

答案 2 :(得分:0)

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

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