Objective-C のプロパティ属性のガイドライン

Objective-C のプロパティの属性を指定するとき従うべきガイドラインをまとめた。

## できる限り `nonatomic` を指定する
`atomic` にしてもパフォーマンスが悪化するだけでほとんどメリットがない（参考：[StackOverflow - Atomic vs nonatomic properties](http://stackoverflow.com/questions/588866/atomic-vs-nonatomic-properties)）。

```objc
@property (nonatomic) id value;
```

`nonatomic` と `atomic` の使い分けの指針は次のとおり：

>
- 参照型: メモリアドレスのみの書き込みなので、常にnonatomicでよい
- プリミティブ型:
    - int, BOOL等ワンステップでの書き込みが可能: 常にnonatomicでよい
    - 単一のスレッドからしかアクセスされない: 設計に気をつけつつnonatomic推奨
    - 複数のスレッドからのアクセスがあり、long,構造体などサイズの大きい値: atomic推奨

([thx to](#comment-bcdf4e94f134605184e8) @takasek)

複数のスレッドから同時に読み書きが行われる可能性があるプロパティには `atomic` を指定する。 `atomic` を指定することで getter と setter が排他的に実行されるようになり、値の書き込みに複数のメモリ操作命令が必要な型（構造体など）が中間状態で読み出されることがなくなる。

`atomic` を指定してもスレッドセーフになるとは限らない点に注意すること。たとえば、 `obj.atomicInt++` を複数スレッドで同時に実行すると、実行した回数より値が小さくなることがある（参考：[Objective-Cでatomicな宣言プロパティがatomicであるとは限らない話｜スマホとアドテク開発記](http://ameblo.jp/tomotaken/entry-10818354164.html)）。

スレッドセーフ性を保証したいときは、 `atomic` よりも `@synchronized` や `NSLock` などの排他制御のほうが適切なこともあるので、よく検討すること。

## `strong` と `assign` は省略してもよい
オブジェクト型のプロパティは `strong` が、それ以外の型のプロパティは `assign` がデフォルトであるため、省略することができる。 `weak` や `copy` のプロパティと桁をそろえるために、あるいは既存のコードとスタイルを一致させるために、明示してもよい。

注：Xcode 4.2.xまでは、オブジェクト型プロパティの `strong` の省略は認められない。

```objc
// 省略
@property (nonatomic) id object;
@property (nonatomic) NSInteger primitiveValue;

// または明示
@property (nonatomic, strong) id object;
@property (nonatomic, assign) NSInteger primitiveValue;
```

## Outlet には基本的に `weak` を指定する
Outlet が参照するオブジェクトは、大抵は何らかのビューのサブビューである。サブビューはそのスーパービューによって保持されるので、 outlet は `weak`で構わない。 `weak` にすることで意図しない循環参照を予防できる。ただし、次のようなオブジェクトを参照する outlet は `strong` にしなければならない：

- Nib のトップレベルオブジェクト（ウィンドウ、他のビューに属さないビュー、 `NSObjectController` などビュー以外のオブジェクト）
- サブビューのうち、 `-removeFromSuperview` を呼ぶなどして一時的にビュー階層から取り除かれる可能性があるもの

（参考：[Managing the Lifetimes of Objects from Nib Files](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6)、[[iOS5] ARC : Outletにはweakプロパティを使おう](http://blog.natsuapps.com/2011/11/ios5-arc-weakproperty-for-outle.html)）

```objc
@property (nonatomic, weak) IBOutlet NSView *view;
@property (nonatomic, strong) IBOutlet NSWindow *window;
@property (nonatomic, strong) IBOutlet NSView *removableView;
```

## デリゲートプロパティには `weak` を指定する
あるオブジェクトをそのオブジェクト自身のデリゲートにするような状況では循環参照が発生するため、デリゲートプロパティを `strong` にするとオブジェクトが解放されなくなる。特別な事情がなければデリゲートプロパティは `weak` にすべきである。

Cocoa のデリゲートプロパティは、 `NSURLConnection` や `CAAnimation` などの例外を除き `weak` か `unsafe_unretained` になっている。

```objc
@property (nonatomic, weak) id delegate;
```

## `weak` 参照してはいけないクラスに注意する
OS X では、 UI に関係するクラスのうちのいくつかが `weak` 参照に対応していない（参考：[
weak 参照してはいけない Cocoa のクラス一覧](http://qiita.com/uasi/items/ee71a476ec3ef9c3c10d)）。これらのクラスを弱参照したい場合は `unsafe_unretained` 参照を使うこと。


## Mutable なサブクラスがある型には `copy` を指定する
`NSString` 型などの、対応する `NSMutable...` 型があるプロパティには `copy` を指定する。Mutable なオブジェクトの `copy` メソッドは immutable なオブジェクトを返すため、プロパティにセットされる値が immutable であることを保証できる。

Immutable オブジェクトの `copy` メソッドは、オブジェクトをコピーせずインスタンス自身を返すため、パフォーマンスが悪化することはない。

```objc
@property (nonatomic, copy) NSString *string;
```

## `readonly` と対応するプロパティには `readwrite` を明示する
あるプロパティをクラス外部からは `readonly` にする場合、クラス内での定義には `readwrite` を明示する：

```objc
/*** Foo.h ***/
@interface Foo
@property (nonatomic, readonly) id value;
@end

/*** Foo.m ***/
@interface Foo ()
@property (nonatomic, readwrite) id value;
@end
```

`readwrite` はデフォルトであり省略可能だが、クラス外に `readonly` で公開するプロパティだけ `readwrite` を明示するルールにすると分かりやすい。

## あるプロパティをヘッダと実装の両方に書くときはオーナーシップ属性を一致させる
下の例のようにオーナーシップ属性が一致していないと、 "ARC forbids synthesizing a property of an Objective-C object with unspecified ownership or storage attribute" とエラーが出る。

```objc
// 誤った指定の例

/*** Foo.h ***/
@interface Foo
@property (nonatomic, readonly) id value; // 暗黙的に `strong` を指定
@end

/*** Foo.m ***/
@interface Foo ()
@property (nonatomic, copy, readwrite) id value; // `copy` を指定
@end
```

## ブロック型のプロパティには `copy` を指定する
関数本体の中に記述されたブロックリテラルの記憶領域はスタックに確保される。ブロックオブジェクトをプロパティにセットするためには、 `copy` メソッドを呼んで記憶領域がヒープに確保されたブロックを作らなければならない。

```objc
typedef void (^MyCallback)(void);
@property (nonatomic, copy) MyCallback callback;
```

ブロック型のプロパティにオーナーシップ属性を指定しないと、暗黙的な `strong` にはならず、  "ARC forbids synthesizing a property of an Objective-C object with unspecified ownership or storage attribute" とエラーが出る。明示的に `strong` を指定しても警告は出ないが、そうすべきではない。

## BOOL 型のプロパティには is で始まる名前の getter を指定する
getter をメソッドとして呼び出すときは名前が is で始まるほうが自然。

```objc
@property (readonly, getter=isBlue) BOOL blue;
```

```objc
if (color.blue) { }
if (color.isBlue) { }
if ([color isBlue]) { }
```

（参考：[Adopting Modern Objective-C](https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html#//apple_ref/doc/uid/TP40014150-CH1-SW4)）

# まとめ

```objc
/*** Foo.h ***/

@interface Foo

// strong や assign は省略可
@property (nonatomic) id object;
@property (nonatomic) NSInteger primitiveValue;

// Outlet は weak にする（トップレベルオブジェクトは strong）
@property (nonatomic, weak) IBOutlet NSView *view;
@property (nonatomic, strong) IBOutlet NSWindow *window;

// Delegate は weak にする
@property (nonatomic, weak) id delegate;

// Mutable なサブクラスがある型は copy にする
@property (nonatomic, copy) NSString *possiblyMutable;

// 後述
@property (nonatomic, readonly) id internallyWritable;
@property (nonatomic, copy, readonly) id internallyWritableByCopy;

// ブロック型は copy にする
typedef void (^MyCallback)(void);
@property (nonatomic, copy) MyCallback callback;

// BOOL 型の getter 名は is で始める
@property (nonatomic, getter=isBlue) BOOL blue;

@end

/*** Foo.m ***/

@interface Foo ()

// 外部から readonly にするプロパティには readwrite を明示する
@property (nonatomic, readwrite) id internallyWritable;
@property (nonatomic, copy, readwrite) id internallyWritableByCopy;

@end

```

# 属性の順序について
属性を並べる順番は任意だが、既存のコードにプロパティを追加するなら周りのスタイルに合わせるべきである。新規に書く場合、筆者は以下の順番を推奨する：

```objc
@property (nonatomic, strong, readonly, getter=foo, setter=setFoo:) id foo;
```

`nonatomic` はほぼ常に指定されるので、 `@property (nonatomic` までを定型文としてとらえる。 `strong` や `weak` も（デフォルト値を省略しないなら）常に必要なので2番目に書く。 `getter` と `setter` は最後に指定する。仮にその後に属性を書くと、 getter/setter 名が長い場合に目で追いづらくなるだろう。