属性の特質

3793 ワード

最近Effective Objective-Cを読みました.冒頭はメモにしましょう.プロパティを使用するときは、プロパティのさまざまな特質(attribute)設定がコンパイラによって生成されるアクセス方法にも影響するという問題に注意する必要があります.この行のコードは3つの特質を指定しています.
@property (nonatomic,readwrite,copy) NSString *firstName;

属性が持つことができる特質は4つに分けられ、以下では一つ一つ説明します.
  • 原子性デフォルトでは、右側で合成された方法は、ロックメカニズムによって原子性(atomic)を確保します.プロパティにnonatomic特質がある場合は、同期ロックは使用されません.nonatomicが宣言されていない場合は、このプロパティがatomicであることに注意してください.アクセスメソッドを自分で定義する場合は,属性特質に合致する原子性に従うべきである.
  • 読み取り/書き込み権限1.readwrite特質を備えた属性にはsetterメソッドとgetterメソッドがあり、属性が@syntehsizeで実現されると、コンパイラは自動的にこの2つのメソッドを生成します.2.readonly特質を備えた属性はgetterメソッドのみを有し、この属性が@synthesizeで実装されている場合にのみ、コンパイラはgetterメソッドを合成する.この特質を使用して、ある属性を読み取り専用属性として公開し、「class-continuation分類」で読み書き属性として再定義できます.このやり方については後述する
  • メモリ管理文のプロパティは、データをカプセル化するために使用されますが、データには特定の所有権が必要です.次の特質は、setterメソッドにのみ影響します.たとえば、setterメソッドで新しい値を設定する場合、retainはこの値を設定するべきですか、それとも最下位のインスタンス変数にのみ値を割り当てるべきですか.コンパイラは,アクセスメソッドを合成する際に,この特性に基づいて生成されるコードを決定する.自分でアクセスメソッドを記述する場合は,属性に関する特質と一致しなければならない.
  • assign setterメソッドでは、基本タイプに対する単純な付与操作のみが実行されます.
  • strongこの特質は、この属性に新しい値を設定すると、setterメソッドが新しい値を保持し、古い値を解放してから、新しい値を
  • に設定する所有関係を定義していることを示しています.
  • weakこの特質は、setterメソッドが新しい値も古い値も保持しない非所有関係を定義していることを示しています.この特質はassignと似ていますが、属性が指すオブジェクトが破壊されると、属性値も空になります.
  • unsafe_unretainedという特質的な意味はassignと同じですが、オブジェクトタイプに適用されます.この特質は非所有関係を表し、ターゲットオブジェクトが破壊されると属性値が自動的に空にならない点でweakとは異なります.
  • copyこの特質が発現する所属関係はstrongと類似している.しかしsetterメソッドは、新しい値を保持するのではなく、copyにします.属性タイプがNSString*の場合、この特質はパッケージ性を保護するためによく使用されます.setterメソッドに渡される新しい値は、NSMutablesStringクラスのインスタンスを指す可能性があるためです.このクラスはNSStringのサブクラスで、修正可能な文字列を表しています.この場合、文字列をコピーしないと、属性を設定した後、文字列の値はオブジェクトが知らないうちに変更されます.したがって、可変文字列をコピーするには、オブジェクト内の文字列の値が何気なく変動しないことを確認します.アトリビュートを実装するオブジェクトが可変である限り、新しい値を設定するときにコピーする必要があります.

  • メソッド名は、アクセスメソッドのメソッド名を以下の特質で指定できます.
  • getter=getterメソッドの名前を指定します.属性がboolタイプで、getterメソッドにis接頭辞を付けたい場合は、このメソッドで指定できます.
     @property (nonatomic, assign,getter=isOn) BOOL on;
    
  • setter=setterメソッドの名前を指定します.この使い方はあまり一般的ではありません.

  • 他の方法で属性値を設定する場合は、属性定義で宣言されている特性を遵守する必要があります.たとえば、前のPersonクラスを拡張します.次の図です.
    @interface Person : NSObject
    @property(copy) NSString *firstName;
    @property(copy) NSString *lastName;
    -(id)initWithFirstName:(NSString *)firstName
                    lastName:(NSString *)lastName;
    @end
    

    初期化方法を追加しましたmファイルでこの初期化方法を実現するには、必ず属性定義のcopyの意味に従い、初期化方法の実現コードはこのように書くべきである.
    -(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName{
        if ((self = [super init])) {
            _firstName = [firstName copy];
            _lastName  = [lastName copy];
        }
        return self;
    }
    

    なぜ対応するsetterメソッドを呼び出さないのかと聞かれるかもしれませんが、setterメソッドを呼び出すと、正確な意味が保証されるのではないでしょうか.次に、init(またはdealloc)メソッドでアクセスメソッドを呼び出さない理由を説明します.
    atomicとnonatomicの違いは何ですか?前述したように,atomic特質を備えたgetter法は,ロック機構によってその原子性を確保する.つまり、2つのスレッドが同じプロパティを読み書きすると、いつでも有効なプロパティ値が表示されます.ロックをかけないと、1つのスレッドが属性値を書き換えている間に、別のスレッドが突然侵入して、まだ修正されていない属性値を読み出してしまう可能性があります.この場合、スレッドが読み取った属性値が間違っている可能性があります.
    iOSプログラムを開発すると、すべてのプロパティがnonatomicとして宣言されていることがわかります.これは、iOSで同期ロックを使用するコストが高く、パフォーマンスに問題があるためです.一般に、属性がatomicである必要はありません.これはスレッドの安全を保証するものではありません.スレッドの安全な操作を実現するには、より深いロックメカニズムを採用する必要があります.たとえば、1つのスレッドが連続して属性値を複数回読み取る過程で別のスレッドが同じことで値を書き換える価値がある場合、属性をatomicと宣言しても、異なる属性値が読み出されます.したがって、iOSプログラムを開発する際には、nonatomicプロパティが一般的に使用されます.
    以下にまとめます.
  • は、@property構文によって、オブジェクトにカプセル化されたデータを定義することができる.
  • は、属性の特質によって、データを格納するために必要な正確な意味を指定する.
  • プロパティに対応するインスタンス変数を設定する場合は、そのプロパティが宣言した意味に従う必要があります.
  • iOSプログラムを開発するには、atomicプロパティがパフォーマンスに深刻な影響を及ぼすため、nonatomicプロパティを使用する必要があります.ここで、次の記事では、オブジェクト内でインスタンス変数にアクセスするには、プロパティを使用するか、インスタンス変数に直接アクセスするかについて説明します.