0

我正在阅读这段代码,发布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];
}

谢谢

4

3 回答 3

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];
}

最后要注意的是:releasedealloc是非常不同的东西。 release不一定会破坏对象。它只是将retain计数减一。如果该retain计数变为零,则只有在那时才会释放对象。所以这段代码有效,因为 arelease发生但没有触发 a dealloc

于 2012-04-04T01:33:13.023 回答
1

以上是非常危险的代码。它可能会起作用,但它只是变得幸运。释放变量后,您永远不应该访问它。事实上,nil如果变量没有立即超出范围,最好在释放变量后立即将其设置为。有些人只在发布模式下这样做,因此创建一个宏,如:

#ifdef DEBUG
#define RELEASE(x) [x release];
#else
#define RELEASE(x) [x release]; x = nil;
#endif

这样做的原因是为了帮助在调试模式下捕获错误(通过崩溃而不仅仅是一个静默nil指针),同时在发布模式下更安全一些。

但在任何情况下,您都不应该在释放变量后访问它。

于 2012-04-04T01:31:21.917 回答
1
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];

(objectA创建,retain count为1,rootViewController指向它)

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

(objectB创建,retain count为1,aNavigationController指向它)(objectA的retain count现在为2,rootViewController和self.aNavigationController中的一些属性都指向它)

self.navigationController = aNavigationController;

(objectB 保留计数现在为 2,aNavigationController 和 self.navigationController 都指向它;假设 self.navigationController 是一个保留属性)

[aNavigationController release];

(objectB 保留计数现在为 1,但是,aNavigationController 和 self.navigationController 都指向它)

[rootViewController release];

(objectA 的保留计数现在为 1,但是 rootViewController 和 self.aNavigationController 中的某些属性都指向它)

[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;
于 2012-04-04T01:41:09.447 回答