2012-04-04 10 views
0

RootViewControllerがリリースされた後にsetRegionsが呼び出されたこのコードを読んでいました。少し奇妙です。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のカウントが0になると、のみ、次にのオブジェクトが割り当て解除されます。したがって、releaseが発生しますが、deallocがトリガーされないため、このコードが機能します。

+0

アレックス・ウェインの答えは – Paul

1

は、上記の非常に危険なコードです。それはうまくいくかもしれないが、それはちょうど幸運になっている。変数を解放した後は、決して変数にアクセスすべきではありません。実際には、即座に範囲外に出ない場合は、すぐに変数をnilに設定してからすぐに変数を設定することをお勧めします。一部の人々は唯一のリリースモードでこれを行う、などのようなマクロを作成します。この理由は、(クラッシュだけではなく、サイレントnilポインタを持っていることによって)デバッグモードでキャッチバグを支援することです

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

、しばらくリリースモードで少し安全です。

いずれにしても、変数を解放した後は、決して変数にアクセスしないでください。

+0

感謝Robネーピアの答えは – Paul

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

は(ObjectAに作成し、カウントが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が保持性である)

[aNavigationController release]; 

(ObjectBに保持カウントそれに対して、しかし、aNavigationControllerとself.navigationController両方の点)について1である

[rootViewController release]; 

(ObjectAに、カウントがしかし、今1の両方rootVを保持iewControllerとそれにself.aNavigationControllerポイント)をObjectAにアクセスするための

[rootViewController setRegions:[Region knownRegions]]; 

(使用rootViewController) でいくつかのプロパティ(これは良くない)

私のお勧めの方法を以下に示します。

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

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

ありがとう、答えはyehnan – Paul

関連する問題