1

ここに興味深い問題があります。私はビューコントローラーを持っています。それをMyViewControllerと呼びましょう。そのメンバーの1つはカスタムビューです。それをMyCustomViewと呼びましょう。MyViewControllerはカスタムビューのデリゲートとして使用されるため、MyCustomViewにはその親であるMyViewControllerへの参照もあります。この問題は、メモリ警告などが原因でMyViewControllerがアンロードされたときに発生します。これが何が起こるかです:

まず、MyViewControllerに対してviewDidUnloadが呼び出されます。これは次のようになります。

- (void)viewDidUnload {
[super viewDidUnload];
    self.myCustomView = nil;
    self.someData = nil;
    ...
}

self.myCustomView = nilが実行されると、myCustomViewの割り当てが解除されます。MyCustomViewのdeallocルーチンは次のようになります。

- (void)dealloc {
    ...
    [delegate release];
    ...
    [super dealloc];
}

上から、デリゲートがMyViewControllerであることを思い出してください。MyCustomViewが最初にリリースされた場合、MyViewControllerの参照数は1より大きいため、これは問題にはなりませんが、この場合、MyViewControllerには他の参照がありません。これにより、MyViewControllerが解放されます。つまり、deallocルーチンが呼び出され、次のようになります。

- (void)dealloc { 
    [myCustomView release];
    [somedata release];
    ...
    [super dealloc];
}

ご覧のとおり、MyViewControllerのメンバー、つまり「somedata」は、MyViewControllerのviewDidUnloadルーチンが完了する前にリリースされます。MyViewControllerとMyCustomViewのdeallocルーチンが完了し、viewDidUnloadルーチンの終了に戻ると、次の行に移動します。

self.somedata = nil;

現在、somedataはnilではありませんが、その値はすでにリリースされています。これにより例外が発生します。

これは、参照カウントの重大な欠陥のようです。このようなオブジェクトで、相互に割り当てを解除する双方向参照をどのように処理しますか?

1つの答えは、deallocルーチンでメンバーを常にnilに設定することです。私はその答えが好きではありません。これは多くの余分な作業であり、ほとんどの場合必要ではないはずです。もう1つの答えは、viewDidUnloadの順序を並べ替えて、後方ポインターを持つ可能性のある子オブジェクトの割り当て解除が常に最後に行われるようにすることです。私もこの解決策が好きではなく、それは時々うまくいかないかもしれません。

この問題をどのように回避しますか?

4

1 に答える 1

5

デリゲートメンバーは通常、参照カウントされません。通常、宣言は次のとおりです。

@property(nonatomic, assign) id<UITableViewDelegate> delegate

このように代理人を作成すれば、問題は発生しません。そして、親ビューコントローラは子ビューと同じくらいの長さしかないので安全なはずです-はい?

于 2010-11-12T23:13:58.043 に答える