続いてはこちら。
(2)@propertyの属性ってなに? ~retain , assign, copy編~
次に、お待ちかね(?)の「retain」、「assign」、「copy」について紐解いていきます。
まず、これら3つ何が違うのか?
ズバッと言いますと、
アクセッサメソッドの実装です。
実際に見てみましょう。
次のようになっています。
--------------------------
@property(assign or retain or copy) NSString *example
@synthesize example;
とした場合、次のような実装がコンパイルによって自動合成される。
//assign属性を指定した場合
- (void)setExample:(NSString*)in {
example = in;
}
// retain属性を指定した場合
- (void)setExample:(NSString*)in {
if (example != in) {
[example release];
example = [in retain];
}
}
// copy属性を指定した場合
- (void)setExample:(NSString*)in {
if (property != newValue) {
[property release];
property = [newValue copy];
}
}
(※属性を指定しなかった場合は自動的にassignになります)
(ARC環境下では自動的にstrong)
--------------------------
まず、assignだが、見た通りreleaseもretainもされていない。引数を単に代入している。
つまり「オブジェクト型でない場合、assignを使用する」という事になる。
主にintやdouble、BOOLと言った変数に使います。
(オブジェクトに対しても使用可能ですが、あまり利用されません)
次にretainとcopyですが、これが少し難しい。
基本的には次の考え方で大丈夫です。
オブジェクトを値として扱っているようなときは、copy
それ以外の場合は、retain
(これに当てはまらない例外も勿論存在します。)
前者のコピーについて、分かりやすかった例はNSString型での宣言です。
@property(retain)NSString *str;
@synthesize str;
NSMutableString *mutableStr = [NSMutableString stringWithFormat@"hello"];
という宣言があったとします。
NSString型は引数として、可変なMutableStringを受ける可能性もあるので、次のような代入も考えられます。
str = mutableStr;
この時、
[mutalbeStr appendString@" World"];
とするとstrもそれに引きずられて中身がHello Worldに変わってしまいます。
このような参照元の値が予期せぬ内に変更されるのを防ぐ目的でcopyの使い方です。
@property(copy)NSString *str;の場合は勿論ですが、
[mutalbeStr appendString@" World"];としても、内容はHelloのままです。
ディープコピーですね。
※注意(どんでん返しなので、結構重要)
ただし、NSStringやNSArrayやNSDictionaryなどのMutableでないオブジェクトはcopyしても、言語仕様のため、
実際にはコピーされず、同じアドレスを指してしまう
のでcopyもretainも同じ意味になります。
ですが、暗黙的な意味でcopyを使うと良いでしょう!
(ちなみにMutable型のオブジェクトはディープコピーされるので、retainとcopyの意味合いは違います)
さてさて、ここまで色々記述してきましたが、copyの使いどころ。
あまりありません。
iphoneアプリ制作では基本的にretainでしょう。
先ほど述べた暗黙的な意味とMutable系のオブジェクトをディープコピーしたい場合にのみcopyを使うイメージで良いと思われます。
それ以外はretainで。
長々と書いてきたので、最後にまとめましょう。
(2)まとめ
assign => intやdouble,BOOLといったオブジェクト型でない変数に使用しよう。
copy => 暗黙的な理由(NSStringやNSValue,NSNumberなどの変数)と
Mutable型の変数をディープコピーしたい場合に使用する。
retain => それ以外!(ビューやラベルやIBOUtlet)
---------------------------
コラム:
他に属性としreadonlyやreadwrite、そして頻繁に見るnonatomicがあります。
これらの属性は理解が簡単なので、ついでに覚えておきましょう。
readonly => 読み取りのみ(ゲッターのみ使用できる)
readwrite => 読み書きOK (ゲッター、セッター使用可能 デフォルト)
nonatomic => スレッドセーフにする。
(要はスレッドを仕様した際に、多重アクセスを生じても、値が破損しないようにする。)
スレッドを使わないなら、nonatomicに指定しておけばOK.
--------------------------
第1回 @property,@synthesizeについて
第3回 weak,strongについて