我正在阅读此代码,其中setRegions
在RootViewController
发布后被调用:我发现它有点奇怪:是否仍然可以访问RootViewController
,即使它已被释放和self.navigationController
"拥有"它?
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the navigation and view controllers
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
[aNavigationController release];
[rootViewController release];
[rootViewController setRegions:[Region knownRegions]];
// Configure and display the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
由于
答案 0 :(得分:4)
这是错误的代码。
对象应该保留另一个对象,只要它关心它。在这种情况下,该规则被打破。 rootViewController
已发布,然后在您注意时,会调用一个方法。这可能很危险。
在这种情况下,它有效。这是因为rootViewController
被传递给另一个保留它的对象。因此,当我们发布它时,它仍然具有正保留计数并且不会被释放。所以我们对它的引用仍然有效,并且调用它的方法工作正常。
但是让我们说一些实现发生了变化,initWithRootViewController:
现在不再因为某些原因而保留了它的论点(假设你不能真正做到这一点)。突然之间,这一切都崩溃了,因为rootViewController
被解除分配。
要解决此问题,您只需将[rootViewController release];
移动到此函数中该对象的最后一个有用引用之后。然后,您的代码将变得更强大,更正确。
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the navigation and view controllers
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
[rootViewController setRegions:[Region knownRegions]];
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
// Release temporary objects since we've now sent them to other other objects
// which may or may not retain them (we don't really care which here)
[aNavigationController release];
[rootViewController release];
// Configure and display the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
最后要注意的是:release
和dealloc
是完全不同的事情。 release
不一定会破坏对象。它只是将retain
计数减1。如果retain
计数变为零,只有才会释放对象。因此,此代码有效,因为发生release
但未触发dealloc
。
答案 1 :(得分:1)
以上是非常危险的代码。它可能会发生作用,但它只是运气好。在释放变量后,永远不应该访问变量。实际上,最好在释放变量后立即将变量设置为nil
,如果它们没有立即超出范围。有些人只在发布模式下执行此操作,因此创建一个宏,如:
#ifdef DEBUG
#define RELEASE(x) [x release];
#else
#define RELEASE(x) [x release]; x = nil;
#endif
这样做的原因是为了帮助捕获调试模式中的错误(通过崩溃而不仅仅是静态nil
指针),同时在发布模式下更安全。
但无论如何,在发布变量之后,你永远不应该访问变量。
答案 2 :(得分:1)
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
(objectA created,retain count为1,rootViewController指向它)
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
(objectB创建,保留计数为1,aNavigationController指向它) (objectA保留计数现在为2,rootViewController和self.aNavigationController中的某些属性指向它)
self.navigationController = aNavigationController;
(objectB保留计数现在为2,aNavigationController和self.navigationController都指向它;假设self.navigationController是一个retain属性)
[aNavigationController release];
(objectB保留计数现在为1,但是,aNavigationController和self.navigationController都指向它)
[rootViewController release];
(objectA保留计数现在为1,但是,selfView.aNavigationController中的rootViewController和某些属性都指向它)
[rootViewController setRegions:[Region knownRegions]];
(使用rootViewController访问objectA) (这不好)
以下是我推荐的方式:
RootViewController *rootViewController = [[[RootViewController alloc] initWithStyle:UITableViewStylePlain] autorelease];
[rootViewController setRegions:[Region knownRegions]];
UINavigationController *aNavigationController = [[[UINavigationController alloc] initWithRootViewController:rootViewController] autorelease];
self.navigationController = aNavigationController;