当我看到Jeff LaMarche的优秀blog时,我正在查看一些示例代码:
- (void)applicationDidFinishLaunching:(UIApplication*)application { CGRect rect = [[UIScreen mainScreen] bounds]; window = [[UIWindow alloc] initWithFrame:rect]; GLViewController *theController = [[GLViewController alloc] init]; self.controller = theController; [theController release]; // ... }
在.h中,我们看到“窗口”和“控制器”是如此声明的ivars:
@interface OpenGLTestAppDelegate : NSObject { UIWindow *window; GLViewController *controller; } @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet GLViewController *controller; @end
我的问题是:为什么“窗口”和“控制器”以不同的方式分配?
我想我理解为什么每种作业都有效(跟踪保留计数),但为什么它们以不同的方式分配?具体来说,为什么不以相同的方式分配控制器窗口是这样的,如果没有通过设置器,那么窗口是:
controller = [[GLViewController alloc] init];
一般来说,何时使用单行方法,何时使用多行方法?
感谢。
答案 0 :(得分:3)
他是否为controller
实例变量创建了自定义setter?
如果是这样,可能会有通过setter更改controller
变量时调用的代码。仅将controller
变量设置为:
controller = [[GLViewController alloc] init];
不会调用setter方法;但是,将新分配的对象分配给局部变量,然后使用:
进行设置self.controller = theController;
会调用setter方法,因为它是一种写作的简写方式:
[self setController:theController];
将执行setter中的额外代码。这通常是您期望区分两种方法的地方。
修改强>
显然,在查看代码之后,他没有实现自定义setter方法,但是当使用时使用的方法仍然是最常用的,当实现自定义setter方法时
我对额外代码背后原因的猜测是他计划在分配后释放变量,如果分配给局部变量,他可以使用局部变量调用setter方法,然后调用release
然后在局部变量上。这总体上比使用
[[self controller] release]
然而,这是一种奇怪的方法,因为setter的综合实现将保留实例变量,然后他在将其设置为实例变量后释放它,并作为release
呼叫取消retain
呼叫,使用单行方法设置变量更有意义。
答案 1 :(得分:2)
额外的代码似乎只是因为他特别想要使用属性(setter方法)。在他的实现(GLView.m)中,-setController
还根据控制器是否响应(实现)-setupView:
方法来设置布尔值ivar。
即便如此,单线解决方案似乎也会起作用:
self.controller = [[[GLViewController alloc] init] autorelease];
与显式消息发送相同的行(没有点语法)也可以使用:
[self setController:[[[GLViewController alloc] init] autorelease]];
任何一种方法都会使新控制器保留适当的保留计数,并仍然根据需要使用setter属性。
(注意:有问题的代码在this blog post末尾链接。)
修改强>
对不起有任何困惑。代码在___PROJECTNAMEASIDENTIFIER___AppDelegate.m
和GLView.m
中都有一个“GLViewController * controller”ivar和属性,我正在查看后者。 (在前者中,setter确实是合成的,它将保留控制器。在第77-81行,你可以看到我提到的代码,他实际上并没有保留控制器 - 只有AppDelegate保留它。)< / p>
在app委托代码中,合成的setter将保留GLViewController,因此我的单行替换建议仍然存在。人们可以争论可读性的两种方式,但对于那些理解保留释放习语的人,我建议单行版本更具可读性。它简洁地传达了意图,甚至提供了一个隐含的暗示,即setter将保留控制器。额外的局部变量实际上只是不必要的毛病。
答案 2 :(得分:2)
正如Quinn指出的那样,可以使用autorelease
方法将对控制器ivar的赋值写入一行。使用更详细版本的原因正是为了避免自动释放并使用手动释放。这是由于Apple建议尽量减少在iPhone上使用自动释放池。因此,您必须将对新分配的对象的引用存储在本地变量中,以便在调用setter后释放它。
考虑何时使用直接赋值给实例变量的问题(如window
ivar的情况)以及何时使用setter方法(如controller
ivar的情况),主要是风格问题,但你最好保持一致。
ivar设置有两种样式:
就个人而言,我认为使用第二种风格会产生更一致和可维护的代码。如果有一天你意识到你的setter必须执行更多工作,你应该只更改setter,而在使用第一个样式时你也应该更改所有出现的直接赋值给setter调用。
刚刚在另一个帖子中找到了对该问题的良好讨论:instance variable/ method argument naming in Objective C。