2

私は弱い参照と強い参照の使用、およびそれらをいつ使用するか、いつ使用しないかに慣れてきており、以下に説明するようなケースになりました(警告に関するコメントを確認してください)

@interface MPIViewController ()
@property (weak, nonatomic) UIView *subview;
@property (weak, nonatomic) UILabel *label;
@end

@implementation MPIViewController
// ...
// some code here
// ...  

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.subview = [[UIView alloc] init];   // warning here: assigning retained object to weak property 
    self.label = [[UILabel alloc] init];    // no warnings

    [self.view addSubView: self.subview];
    [self.view addSubView: self.label]; 
}

// ...
// some code here
// ...  
@end

の説明から- (void)addSubview:(UIView *)view:

このメソッドは、ビューへの強力な参照を確立し、次のレスポンダーを新しいスーパービューであるレシーバーに設定します。

これは、このオブジェクトがdeallocatedメソッドの終了後に存在しないことを意味します。これは、オブジェクトsuperviewを保持し、強い参照を保持するため、スーパービューが存在する限り、このビューがメモリに保持されるためです。私はここにいますか?

ここでの割り当てを正しく理解しているかどうかもわかりません。警告は、割り当ての直後になると言っていますが、コードの次の行でdeallocated得られるように、弱いポインターに変数を割り当てることができないため、これは間違っているように聞こえますか?deallocated

UILabel同じ割り当ての場合は正常に機能しますが、そうUIViewではありませんか? コンパイラは UIView をどうにかして扱いますか? これは、それがどのように可能であるかを本当に困惑させます。

このコードは、UIView をローカル メソッド変数に割り当ててから、次のようにセッターに渡すだけで簡単に修正できます。

UIView *tmpView = [[UIView alloc] init];
self.subview = tmpView;

メソッドで宣言された変数はデフォルトであり、strongそのような構造を持つことで警告が削除されます。これは、コンパイラがこの変数に強い参照があると見なすため、メソッド変数がそれを指している限り、その後に割り当てられる弱い参照が保持されるためです。しかし!tmpView はローカルメソッド変数にすぎず、メソッドが終了した後にダンプされるので、それはどのように意味がありますか?

4

2 に答える 2

2

最初の質問へ:

詳しく見てみましょう。

self.subview = [[UIView alloc] init];

[UIView alloc]所有権が +1 のインスタンスを返します。これは (非表示の) 強い参照に割り当てられ、selfofを構築し-initます。-init所有権を渡します。(元の受信者ではないインスタンスを返す場合、これは正しくありませんが、あなたのケースでは十分な詳細です。)したがって、の戻り値も所有権の譲渡-initと考えることができます。-init

このインスタンスを弱い変数に割り当てます。この瞬間、それは解放されることができます。(読んでください:ARCはすぐにそれを行うことを約束していません、IIRC。)インスタンス変数はnil、オブジェクトがそのスーパービューによって保持される前にある可能性があります。したがって、このコードは危険です:

self.subview = [[UIView alloc] init];
// _subview can be nil'ed
[self.view addSubView: self.subview]; // add nil

これがあなたの問題だとは思いませんが、問題になる可能性があります。– もう一度考えてみると、それあなたの問題です。最後に編集を読んでください。–それを取り除くには、単純に強力なローカル変数を使用します:

UIView *subview = [[UIView alloc] init]; // defaults to __strong
[self.view addSubView: subview]; // adds an ownership
self.subview = subview;

2 番目の質問:

2番目のケースでコンパイラが警告を出さない理由はわかりません。最初のケースを修理するとどうなりますか?

最初のインスタンスが解放されるとき、未定義であるため、実行時に両方のケースの異なる処理が可能です。おそらく、最適化の一環として、ポインターが再利用されます。より詳細な:

__strong id completlyHiddenCompilerGeneratedVar;
… = [(completlyHiddenCompilerGeneratedVar=[UIView alloc]) init];
… = [(completlyHiddenCompilerGeneratedVar=[UILabel alloc]) init];

最初のインスタンスは、内部の強い参照を上書きするため、2 番目のインスタンスが作成されるときに解放されます。

繰り返しますが、最初のケースを修復して、2 番目のケースがどうなるか教えてください。

于 2013-10-29T13:58:59.990 に答える
0

オブジェクトをメモリに保持するには、オブジェクトへの強いポインタが少なくとも 1 つ必要です。

したがって、それを弱いポインターに割り当てると、その条件は満たされません。strongこれらのビューに本当にアクセスする必要がある場合は、プロパティを作成してください。

于 2013-10-29T11:50:03.860 に答える