4

我一直想知道为什么所有的苹果代码示例都使用这样的代码:

UINavigationController *aNavigationController = [[UINavigationController alloc]
          initWithRootViewController:rootViewController];

self.navigationController = aNavigationController;

[self.view addSubview:[navigationController view]];

[aNavigationController release];

他们总是创建一个局部变量并将其分配给 ivar 为什么他们不简单地这样做:

self.navigationController = [[UINavigationController alloc]
          initWithRootViewController:rootViewController];;

[self.view addSubview:[navigationController view]];

[navigationController release];

除了更容易理解之外,还有其他原因吗?这是最佳做法吗?

-奥斯卡

4

5 回答 5

2

您的替换代码不正确,因此说明了 Apple 试图阻止的问题。这是您的代码:

self.navigationController = [[UINavigationController alloc]
      initWithRootViewController:rootViewController];

[self.view addSubview:[navigationController view]];

[navigationController release];

你遗漏了“自我”。在您的参考文献中。也许您打算直接访问 ivar,但在这种情况下,您通过混合访问器和直接 ivar 访问创建了非常混乱的代码(并且通过在访问器外部使用直接 ivar 访问违反了基本规则)。如果不是,那么您的意思是这样写:

self.navigationController = [[UINavigationController alloc]
      initWithRootViewController:rootViewController];

[self.view addSubview:[self.navigationController view]];

[self.navigationController release];

最后一行是非常错误的。永远不要将 -release 发送到方法调用的结果。所以不,你这样做的方式是不正确的。

也就是说,苹果和我在如何做到这一点上存在分歧。这是我的做法:

self.navigationController = [[[UINavigationController alloc]
      initWithRootViewController:rootViewController] autorelease;

[self.view addSubview:[self.navigationController view]];

我喜欢 -autorelease 因为我发现它可以防止错误。分配和释放获取的距离越远,开发人员注入内存泄漏的可能性就越大(例如通过添加“返回”)。自动释放通过将保留和释放保持在一起来避免这种情况,使将其用作临时变量的意图更加清晰,并且通常使代码审查更加容易。

Apple 在他们的示例代码中倾向于不同意我的观点,因为他们通过使用发布而不是自动发布来强调性能。我发现这是错误的优化,因为在任何情况下都不会在此运行循环期间释放该对象(因此不会节省内存),并且我相信自动释放的非常小的性能损失可以弥补减少由于不正确使用释放而导致的内存泄漏。

自动发布与发布的争论充满了灰色阴影(我当然直接在循环中使用发布),并且不同的开发人员有不同的方法,但是在任何一种情况下,您的替换代码都不是正确的方法。

于 2010-02-05T23:07:26.520 回答
1

第一行的不同之处在于 Apple 的版本将对象创建和分配给 ivar 分开,而您的版本将两者放在一起。从概念上讲,Apple 的版本更容易理解。据我所知,这不是最佳实践。

于 2010-02-05T22:37:32.823 回答
1

两个版本都错过了对 nil 值的检查:

(假设 self.navigationController 是一个保留其值的属性)

self.navigationController = [[UINavigationController alloc]
    initWithRootViewController:rootViewController];
if (self.navigationController != nil) {
    [self.view addSubview: navigationController.view;
    [self.navigationController release];
}

你可能会说这是一种风格,但在我看来,它可以减少错误代码。

于 2010-02-05T22:41:41.930 回答
1

它可能与顶级示例相同,但有可能不会。

请记住

self.navigationController = aNavigationController;

是相同的

[self setNavigationController:aNavigationController];

而且您不知道该setNavigationController方法内部发生了什么。它可能正在初始化一个不同的对象并将其设置为 iVar,然后您将其释放,从而导致崩溃。

于 2010-02-05T22:42:49.153 回答
0

因为很明显代码正在使用 UINavigationController 实例变量。那么就没有理由这样做了:

self.navigationController = aNavigationController

如果你不保留它。

但是,如果你这样做:

 self.navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];

之后,如果你像这样释放它:

[navigationController release];

似乎我们正在释放应该在初始化导航控制器的当前类的生命周期内保留的实例变量。所以,很容易出错,让初学者认为它应该只在dealloc方法中释放。

两种方法最终都将保留计数为 0。如果在 dealloc 实现中:

[navigationController release]; // 1 for the ivar
[super dealloc]; // 0 for the retained subviews
于 2010-02-05T23:01:15.543 回答