@propertyの属性 strong と weak

 

よくよく考えると?だった、@propertyの属性の「strong」と「weak」について

あっちこっちの資料を調べた結果、一応、こういうことなんじゃないかということを整理してみました。

間違っていたら、ごめんなさい。

 

確認環境:Xcode 7.2

 

まずは、動かして確認しましょう。

 

strong属性の「strongProperty」weak属性の「weakProperty」という2つのプロパティを持つ

「TESTClass001」クラスのクラスインターフェースを定義します。

なお、@propertyの属性は特に何も指定しなければ、「strong」になります。

 

TESTClass001.h

「viewDidLoad」で以下のような処理を行います。

 

ViewController.m

実行結果は、以下の通りです。

2回目のNSLogの結果で、「weakProperty」の値が Null になってます。


Tip_01_01_008a

 

行ごとに説明していきます。

 

12行目: TESTClass001 *testClass = [[TESTClass001 alloc]init];

「testClass」という「TESTClass001」クラスのインスタンスを生成します。

 

14行目: NSString *string = [[NSString alloc]initWithFormat:@”変更前”];

NSString型「string」オブジェクトを「alloc」して「init」します。

「alloc」すると、オブジェクトは、メモリ領域に割り当てられます。

ついでですが、割り当てたメモリ領域は、たまたまその領域に残っていた「ゴミ」の影響がないように0が埋めらます。

そして「init」で初期値 ”変更前” を設定します。

 

おそらくですが、イメージとして、メモリ領域にこんな感じで「string」オブジェクトが割り当てられます。

(アドレスは適当です。)


Tip_01_01_008b

 

ここで注目する点は、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」から ”変更前” への強い参照がある、と言います。


Tip_01_01_008c

 

17行目: testClass.weakProperty = testClass.strongProperty;

「testClass.weakProperty」に「testClass.strongProperty」の参照先 ”変更前” のアドレスがセットされます。

「testClass.weakProperty」は「weak」属性のプロパティです。

「weak」属性のプロパティからの参照は参照カウンタを変化させません。

なので、testClass.strongProperty」の参照先 ”変更前” の「参照カウンタ」は、この時点で2のままです。

 

このことを「testClass.weakProperty」は ”変更前” を所有していない、とか

「testClass.weakProperty」から ”変更前” への弱い参照がある、と言います。


Tip_01_01_008d

 

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になります。


Tip_01_01_008e

 

23行目: testClass.strongProperty = string;

「testClass.strongProperty」に「string」オブジェクトの参照先 ”変更後” のアドレスがセットされます。

「testClass.strongProperty」は「strong」属性のプロパティです。

「strong」属性のプロパティからの参照は参照カウンタを+1します。

なので、「string」オブジェクトの参照先 ”変更後” の「参照カウンタ」は、この時点で2になります。

一方、14行目で生成した「string」オブジェクトの参照先 ”変更前” の「参照カウンタ」は、

「testClass.strongProperty」からの参照がなくなるので、−1され0になります。


Tip_01_01_008f

 

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で使用する属性です。