为什么iPhone示例代码使用了这么多中间变量?
我目前正在研究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
的函数)中释放是否有一些优势? 或者在你的dealloc
方法中release
这样的release
同样可以吗?
谢谢你的帮助,
-j
假设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属性。
@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
,一次通过property。 现在[obj release]
一次是不够的。 你需要释放它两次以避免泄漏,自然释放两次是非常糟糕的,并可能导致进一步的内存泄漏。 如果您再次调用self.obj = anotherObj
那么您将泄漏旧的。 为避免这种情况,您需要此临时指针。
有两个原因我可以想到我的头脑; 第一个,更具体的例子,是你经常会看到类似的方法,其中blueController
被分配和初始化,然后在实际被分配给self
的ivar之前测试有效性。 在每个这样的方法中遵循这种模式将使您更容易在创建对象和分配对象之间进行测试,如果您意识到需要发生的话。 据我所知,如果这样的中介确实仍然是多余的,编译器应该优化它。
Cocoa中这种模式的第二个更通用的目的就是Obj-C和Cocoa为方法和变量鼓励极长的冗长名称,因此单个方法调用最终可能跨越多行; 使用方法调用作为其他方法的直接参数很快就会变得不可读,因此约定鼓励提前为方法设置每个参数,将它们放在中间变量中,然后使用变量作为参数来增强可读性,并使其更容易更改一个参数,无需挖掘嵌套方法调用。