释放对象后调用方法?

Posted

技术标签:

【中文标题】释放对象后调用方法?【英文标题】:call a method after the object is released? 【发布时间】:2012-04-04 01:26:35 【问题描述】:

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

谢谢

【问题讨论】:

【参考方案1】:

这是错误的代码。

一个对象应该保留另一个对象,只要它关心它。在这种情况下,这条规则被打破了。 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 计数变为零,只有在之后对象才会被释放。所以这段代码有效,因为发生了release,但没有触发dealloc

【讨论】:

【参考方案2】:

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

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

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

但无论如何,你不应该在释放变量后访问它。

【讨论】:

【参考方案3】:
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的retain count现在是2,aNavigationController和self.navigationController都指向它;假设self.navigationController是一个retain属性)

[aNavigationController release];

(objectB的retain count现在是1,但是aNavigationController和self.navigationController都指向它)

[rootViewController release];

(objectA的retain count现在是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;

【讨论】:

以上是关于释放对象后调用方法?的主要内容,如果未能解决你的问题,请参考以下文章

SynchronizationLockException(对象同步方法是从未同步的代码块中调用的。)释放锁时

释放()异常后调用的方法无法使用android相机恢复

对象被释放但没有调用 dealloc

在 dealloc 中调用 self 的方法

Java sleep()和wait()的区别

media player的四种模式