2012-04-04 42 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