2012-04-04 43 views
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

这是错误代码。

的对象应该保留另一个对象,只要它关心它。在这种情况下,这个规则被破坏了。发布了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

+0

谢谢亚历克斯韦恩的答案 – Paul 2012-04-05 01:24:05

1

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

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

这样做的原因是为了帮助在调试模式下捕捉的错误(由具有崩溃,而不仅仅是一个无声nil指针),而在发布模式下更安全一些。

但在任何情况下,你已经发布后,你永远不应该访问的变量。

+0

感谢罗布纳皮尔回答 – Paul 2012-04-05 01:23:41

1
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain]; 

(对象A创建的,保留计数为1,RootViewController的点到它)

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

(对象B创建的,保留计数为1,aNavigationController指向它) (对象A保留计数现在是2 ,都是rootViewController和自己的一些属性。aNavigationController点到它)

self.navigationController = aNavigationController; 

(对象B保留计数是2现在,既aNavigationController和self.navigationController指向它;假设self.navigationController是一个保留属性)

[aNavigationController release]; 

(对象B保留计数是1现在,但是,既aNavigationController和self.navigationController点到它)

[rootViewController release]; 

(对象A保留计数为1现在,但是,既rootV iewController和self.aNavigationController指向它)

[rootViewController setRegions:[Region knownRegions]]; 

(使用RootViewController的访问对象A) 某些属性(这是不好的)

以下是我推荐的方法:

RootViewController *rootViewController = [[[RootViewController alloc] initWithStyle:UITableViewStylePlain] autorelease]; 
[rootViewController setRegions:[Region knownRegions]]; 

UINavigationController *aNavigationController = [[[UINavigationController alloc] initWithRootViewController:rootViewController] autorelease]; 
self.navigationController = aNavigationController; 
+0

谢谢你的答案 – Paul 2012-04-05 01:20:11