最終更新:2013-01-10 (木) 11:40:51 (4116d)  

@property
Top / @property

プロパティを宣言する

@property (attributes) type name;

概要

アクセッサの名前

  • プロパティに対応するgetterメソッドとsetterメソッドのデフォルトの名前は、それぞれpropertyName とsetPropertyName?:
    • 「foo」というプロパティの場合、アクセサメソッドはfoo とsetFoo:になる
  • アクセサメソッドを別の名前にしたい場合は、属性の形で指定する
    • ブール型(値がYESまたはNO)のプロパティには、ゲッタメソッドを「is」で始まる名前にする慣習がある
      • @property構文では、アクセサメソッド名を別途指定できるようになっていますが、それはブール型プロパティの場合に限定してください。
      • この規約に従わないと、キー値コーディング(KVC、valueForKey?およびsetValue:forKey?でプロパティを取得/設定)がうまく働きません
        @property (getter=isFinished) BOOL finished;

書き方

Xcode 4.4

  • @synthesize@dynamicも書かなかった場合には@synthesizeを付けたのと同じ扱いとなる
    // ViewController.h
    @property (strong) NSString* testString;
    
    // ViewController.m
    @synthesize testString;//@synthesize testString = _testString;
  • // ViewController.h
    @property NSString* testString;//インスタンス変数名は_testString
  • デフォルトがstrongなので書かなくてよくなった
  • @synthesizeされる相手のインスタンス変数は、同名の変数ではなくてアンダーバーを最初に付けた物がデフォルト

インスタンス変数の省略 (Modern Runtimeのみ)

  • There are differences in the behavior of accessor synthesis that depend on the runtime:
    • For the legacy runtimes, instance variables must already be declared in the @interface block of the current class. If an instance variable of the same name as the property exists, and if its type is compatible with the property’s type, it is used—otherwise, you get a compiler error.
    • For the modern runtimes, instance variables are synthesized as needed. If an instance variable of the same name already exists, it is used.
  • iOS always uses the modern runtime so you never need to declare ivars explicitly.
    • that's either iOS 3.x or greater, or 64-bit Snow Leopard or greater
    // ViewController.h
    @interface ViewController : UIViewController{
    NSString* testString;
    }
    @property (strong) NSString* testString;
    
    // ViewController.m
    @synthesize testString;
  • // ViewController.h
    @property (strong) NSString* testString;
    
    // ViewController.m
    @synthesize testString;
  • @synthesizeディレクティブがあれば、インスタンス変数が宣言されていなくても自動的に生成される。

古い書き方

  • インスタンス変数、@property@synthesizeが必要
    //プロパティの属性を宣言@interface(.h)のほうに書く
    @interface HogeObject:NSObject{
        NSString *hoge, *huga;
    }
    @property(copy,readwtire) NSString *hoge,*huga;
    @end
    
    //@implementationのほう(.m)に書く
    @implementation HogeObject
    @synthesize hoge,huga; 
    //@dynamicとした場合は、@propertyで宣言しても自前で実装する(アクセサが生成されない)
    //@synthesize hoge= _hogeValue;//アクセサ名(hoge)とインスタンス変数名(_hogeValue)とを変えるとき
    @end

属性

アクセッサの名前指定

  • getter取得メソッドの名前を指定
    setter設定メソッドの名前を指定

アクセス制限

  • readwrite? (デフォルト)読み書き可能。(getter/setterを生成)
    readonly読み取り専用(setterのみ生成)

setterアクセッサの挙動

Automatic Reference Counting無効時

  • assign (デフォルト)setterで、単純代入を使用することを指定 (参照カウントはそのまま)
    retain代入時にオブジェクトに対してretainを呼び出す必要があることを指定
    以前の値にはreleaseメッセージが送信される。
    copy代入にオブジェクトのコピーを使用することを指定
    以前の値にはreleaseメッセージが送信される。NSCopying?

Automatic Reference Counting有効時

  • strong対象オブジェクトに対する強い(所有権を伴う)関係がある旨を指定
    weak対象オブジェクトに対する弱い(所有権を伴わない)関係がある旨を指定
    対象オブジェクトが割り当て解除されると、プロパティ値は自動的にnilになりる
    (弱いプロパティは、Mac OS X 10.6iOS 4では未対応なので、代わりにassignを使う)。
    copy代入にオブジェクトのコピーを使用することを指定
    以前の値にはreleaseメッセージが送信される。NSCopying?
    unsafe_unretainediOS 4では、weak属性が使えないため、オーナーシップ権を持たないプロパティを作成したい場合に利用

スレッドの制御

  • atomic(デフォルト)スレッドセーフ
    nonatomicアクセサが非アトミックであることを指定(デフォルトではアトミック)
    アクセスする際にロックを行わない。スレッド使わないときはnonatomic

使いどころ

strong

weak

atomic

  • 異なるスレッドからいくつか同時に呼び出したとしても、完全な形で値を取得/設定できる代わりにレスポンスが遅くなる。
  • strongcopyretainのいずれかを指定し、nonatomicを指定しない場合、参照カウント環境では、オブジェクトプロパティ用に合成されたgetterアクセサは、ロックを使用し、戻り値の保持と自動解放を行います。その実装は、次のようになります。
    [_internal lock]; // オブジェクトレベルのロックを使用してロックする
    id result = [[value retain] autorelease];
    [_internal unlock];
    return result;
  • アトミックなアクセサメソッドの内部的な実装や同期機構は非公開なので、自動生成されたアクセサと独自に実装したアクセサメソッドを組み合わせることはできない
    • アトミックなreadwriteのプロパティに対して、セッタを独自実装しゲッタは自動生成に任せようとするとコンパイラから警告される

nonatomic

  • nonatomicを指定した場合は、オブジェクト用に合成されたアクセサは、単に値を直接返すだけ
    • 異なるスレッドから同時にアクセスしたときの結果は保証されない
  • その代わり、アトミックでないプロパティはアクセス処理が高速
  • ゲッタのみ独自に実装して組み合わせることも可能

関連

参考