在释放对象后调用方法?

时间:2012-04-04 01:26:35

标签: objective-c uinavigationcontroller release

我正在阅读此代码,其中setRegionsRootViewController发布后被调用:我发现它有点奇怪:是否仍然可以访问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];
}

由于

3 个答案:

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

最后要注意的是:releasedealloc是完全不同的事情。 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;