@propertyの属性 strong と weak
Update on March 18, 2016
よくよく考えると?だった、@propertyの属性の「strong」と「weak」について
あっちこっちの資料を調べた結果、一応、こういうことなんじゃないかということを整理してみました。
間違っていたら、ごめんなさい。
確認環境:Xcode 7.2
まずは、動かして確認しましょう。
strong属性の「strongProperty」weak属性の「weakProperty」という2つのプロパティを持つ
「TESTClass001」クラスのクラスインターフェースを定義します。
なお、@propertyの属性は特に何も指定しなければ、「strong」になります。
TESTClass001.h
「viewDidLoad」で以下のような処理を行います。
ViewController.m
実行結果は、以下の通りです。
2回目のNSLogの結果で、「weakProperty」の値が Null になってます。
行ごとに説明していきます。
12行目: TESTClass001 *testClass = [[TESTClass001 alloc]init];
「testClass」という「TESTClass001」クラスのインスタンスを生成します。
14行目: NSString *string = [[NSString alloc]initWithFormat:@"変更前"];
NSString型「string」オブジェクトを「alloc」して「init」します。
「alloc」すると、オブジェクトは、メモリ領域に割り当てられます。
ついでですが、割り当てたメモリ領域は、たまたまその領域に残っていた「ゴミ」の影響がないように0が埋めらます。
そして「init」で初期値 ”変更前” を設定します。
おそらくですが、イメージとして、メモリ領域にこんな感じで「string」オブジェクトが割り当てられます。
(アドレスは適当です。)
ここで注目する点は、ARC(Automatic Reference Counting、自動参照カウント)では、
オブジェクトは「参照カウンタ」を持っているということです。
オブジェクトを生成すると、「参照カウンタ」は1になります。
なので、「string」オブジェクトの参照先 ”変更前”の「参照カウンタ」は、この時点で1になります。
16行目: testClass.strongProperty = string;
「testClass.strongProperty」に「string」オブジェクトの参照先 ”変更前” のアドレスがセットされます。
「testClass.strongProperty」は「strong」属性のプロパティです。
「strong」属性のプロパティからの参照は参照カウンタを+1します。
なので、「string」オブジェクトの参照先 ”変更前” の「参照カウンタ」は、この時点で2になります。
このことを「testClass.strongProperty」が ”変更前” を所有している、とか
「testClass.strongProperty」から ”変更前” への強い参照がある、と言います。
17行目: testClass.weakProperty = testClass.strongProperty;
「testClass.weakProperty」に「testClass.strongProperty」の参照先 ”変更前” のアドレスがセットされます。
「testClass.weakProperty」は「weak」属性のプロパティです。
「weak」属性のプロパティからの参照は参照カウンタを変化させません。
なので、testClass.strongProperty」の参照先 ”変更前” の「参照カウンタ」は、この時点で2のままです。
このことを「testClass.weakProperty」は ”変更前” を所有していない、とか
「testClass.weakProperty」から ”変更前” への弱い参照がある、と言います。
19行目: NSLog(@"strongProperty = %@ weakProperty = %@", testClass.strongProperty, testClass.weakProperty);
「testClass.strongProperty」と「「testClass.weakProperty」」の値を確認します。
strongProperty = 変更前 weakProperty = 変更前
となっています。
22行目: string = [[NSString alloc]initWithFormat:@"変更後"];
再度、NSString型「string」オブジェクトを「alloc」して「init」します。
14行目で、「alloc」したのと別のメモリ領域にオブジェクトを生成します。
22行目で、「string」オブジェクトを新たに生成したので「string」オブジェクトの参照先 ”変更後”の「参照カウンタ」は、1になります。
一方、14行目で生成した「string」オブジェクトの参照先 ”変更前”の「参照カウンタ」は、
14行目で、生成した「string」オブジェクトの参照がなくなるので、−1され1になります。
23行目: testClass.strongProperty = string;
「testClass.strongProperty」に「string」オブジェクトの参照先 ”変更後” のアドレスがセットされます。
「testClass.strongProperty」は「strong」属性のプロパティです。
「strong」属性のプロパティからの参照は参照カウンタを+1します。
なので、「string」オブジェクトの参照先 ”変更後” の「参照カウンタ」は、この時点で2になります。
一方、14行目で生成した「string」オブジェクトの参照先 ”変更前” の「参照カウンタ」は、
「testClass.strongProperty」からの参照がなくなるので、−1され0になります。
25行目: NSLog(@"strongProperty = %@ weakProperty = %@", testClass.strongProperty, testClass.weakProperty);
「testClass.strongProperty」と「「testClass.weakProperty」」の値を確認します。
strongProperty = 変更後 weakProperty = (null)
となっています。
ここまでの処理で、14行目で、生成した「string」オブジェクトの参照先 ”変更前”の「参照カウンタ」は、0になりました。
ARCでは、オブジェクトは「参照カウンタ」が0になると、割り当てが解放されます。
「testClass.weakProperty」からの参照が残っていますが、
「testClass.weakProperty」はweak属性のプロパティなので、
弱い参照があるだけでは、オブジェクトの寿命を保つことはできません。
なので、14行目で、生成した「string」オブジェクトの参照先 ”変更前” は解放され、その結果、「testClass.weakProperty」はnilになります。
補足:
このように、プログラムが動的に確保したメモリ領域のうち、不要になった領域を自動的に解放する機能のことを ガベージコレクション(garbage collection; GC)といいます。
Objective-Cでは、ガベージコレクションとして、参照カウント方式を採用しています。
参照カウント方式には、
・MRR(Manual Retain-Release、明示的に記述したコードによる獲得と解放)
・ARC(Automatic Reference Counting、自動参照カウント)
の2つの手段があります。
「strong」と「weak」プロパティの属性は、ARCで使用する属性です。