0

非常に単純な割り当てが散発的に失敗するプロジェクトを書いています。この結果に魅了され、皆さんがどう解釈するか知りたいと思っています。

大規模なデータ セットを含むプロジェクトがあり、モーダル ウィンドウを作成して表示し、新しいクラス インスタンスに関する詳細を表示しています。したがって、次のコードを使用して、カスタム ウィンドウ コントローラー クラスを含むウィンドウを取得しました。

MyWindowController.h:

#import <DataModel.h>

@interface MyWindowController : NSWindowController
@property (nonatomic, weak) FooClass *fooInstance;
@end

MyWindowController.m:

@implementation MyWindowController

@synthesize fooInstance = _fooInstance;

-(void) init {
    self = [super init];
    if (self) {
       self.fooInstance = [FooClass new];
    }
    return self;
}

@end

完全にクッキーカッターですよね?しかし、最初にフォームを追加して何度も実行したとき、割り当ては何度も失敗しました。self.fooInstance は nil として返され続けました。FooClass イニシャライザが実行されており (ステップ実行)、有効な FooClass インスタンスへの非 null ポインタが返されていることも確認しました。それでも、代入行の後、self.fooInstance は null のままでした。

この同じ結果を何度も何度も見て、何度も実行しました。次に、割り当てステートメントだけを次のように置き換えました。

FooClass *foo = [FooClass new];
self.fooInstance = foo;

...そして、割り当てが突然機能し始め、それ以来一貫して実行されています。コードを self.fooInstance = [FooClass new] に戻しても、完全に機能します。

信じられませんでした...同じプロジェクトで、別のクラスの同じタイプのウィンドウを叩きながら、それが再び起こるのを見るまで。

何が起こっているのかわかりません。self.fooInstance アクセサーは完全に @syntheized です。バックグラウンドで実行されている、クラスに混乱している可能性のあるコードはありません (シングルスレッドのモーダル ウィンドウです)。クラスに縛られるものは何もありません。ただ...うまくいきません。ウィンドウクラスのコードは、それを壊すために数回実行するまで正しく実行されないようです.

世界で何が起こっているのですか?この振る舞いを説明するかもしれない推測を危険にさらす人さえいますか?

4

1 に答える 1

3

Mike Ash のウィーク ポインターの説明を一読することをお勧めします。このセクションは関連するビットです。

弱参照

まず、弱参照とは?簡単に言うと、弱参照とは、そのオブジェクトの存続に関与しないオブジェクトへの参照 (Objective-C の世界ではポインター) です。たとえば、メモリ管理を使用して、このセッターは新しいオブジェクトへの弱参照を作成します。

- (void)setFoo: (id)newFoo
{
    _foo = newFoo;
} 

セッターは保持を使用しないため、参照は新しいオブジェクトを存続させません。もちろん、他の参照によって保持されている限り、それは存続します。しかし、それらがなくなると、_foo がまだオブジェクトを指していても、オブジェクトの割り当てが解除されます。

これで最初の部分は説明できましたが、なぜ 2 番目の部分が機能するのでしょうか?

さて、次のようなインスタンス変数を書くと:

FooClass *foo = //assignment

コンパイラーは、「これを維持するのは本当に良い考えです (少なくとも関数が ARC の範囲外になるまで)、これを次のように変換します。

__strong FooClass *foo = //assignment

つまり、割り当てたものはすべて保持されるので、少なくとも 1 つのオブジェクトがそれを所有しているため、それを弱いインスタンス変数に割り当てることができます。

于 2012-08-30T01:56:54.873 に答える