

プロパティとインスタンス変数について、質問があります。

------ サンプル1
[code]

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property (weak, nonatomic) IBOutlet UITextField *text1;
    
    @end
    
    @implementation ViewController
    
    -(void)viewDidLoad {
        [super viewDidLoad];
        self.text1.text = @"test";
    }
    
[/code]

------ サンプル2
[code]

    #import "ViewController.h"
    
    @interface ViewController () {
        __weak IBOutlet UITextField *text1;
    }
    
    @end
    
    @implementation ViewController
    
    -(void)viewDidLoad {
        [super viewDidLoad];
        text1.text = @"test";
    }
    
[/code]

上記の２つを実行すると、どちらもTextFieldにtestと表示されます。

サンプル1ですが、`_text1.text = @"test"` でも表示されます。  
これも意味は理解できます。

ただどういった状況でプロパティに宣言するか、インスタンス変数として宣言するか、使い道が理解出来ません。  
だんだん迷ってどうすれば？って感じになってます。

どなたか教えて頂けないでしょうか。よろしくお願いします。

環境ですが、  
OS X 10.9.5  
Xcode6.1.1  
です。


CC BY-SA 3.0
2015-02-05T10:08:13.450
5993
2015-02-06T11:03:59.870
2015-02-05T10:11:49.677
49
6108
question
objective-c
プロパティとインスタンス変数について


ARC(Automatic Reference Counting)が有効かどうかで2パターンの回答が考えられます。まず、ARCが有効であると仮定します。

`@property`は、その記述とともに指定した名前をもつ **プロパティ**
のsetter/getterの宣言（および、必要に応じてその実装も）を提供するシンタックスシュガーです。  
（端折って言えば）プロパティ及びsetter/getterは、カプセル化を実現するためのコンセプト（抽象化手法）の一つです。それを利用するモチベーションは、作ろうとしているオブジェクトの外部仕様（インターフェイス）  
に「属性の集合からなる何か」というモデルを適用した上で、そのインターフェイスに属性値の読み書きの操作方法を提供するところからきています。

一方、 **インスタンス変数**
は、オブジェクトが望んだように機能するために、クラス製作者が機能を記述するために利用できる、インスタンスに対応した変数です。ただの入れ物です。基本的にはオブジェクトの中からしか参照／更新できませんし、そうなっていないとしたら、そのオブジェクトはオブジェクトなのにオブジェクトという形で抽象化しきれていないのでオブジェクトではありません。

なので、インスタンス変数は外部仕様を記述するヘッダー(.h)上の`@interface {}`内に記述するよりも、ソースコードファイル(.m,
.mm)の`@implementation {}`に記述するのが好ましいです。`@property`は（基本的に）その逆です。

それぞれの特徴をまとめると、以下のようになると思います。使い分けるときに参考にしていただければと思います。

  * プロパティ（＝`@property`）  
  

    * オブジェクトの外部仕様（インターフェイス）を表現するための表現方法（見せ方）
  

    * ヘッダーファイル(.h)で宣言されている
  

  * インスタンス変数  
  

    * オブジェクトの機能を記述するためのアルゴリズムに都合がいいように使う（入れ物）
  

    * ソースファイル(.m, .mm)の中からしか見えない（基本的には）
  

ARCが無効な世界では、変数の代入によって自動的にオブジェクトがretain/releaseされないため、自前で管理しなくてはなりません。  
`@property(retain)`にはプロパティへのset時に自動的にretain/releaseをしてくれるという機能があるので、普通のインスタンス変数を使うより楽できます。


CC BY-SA 3.0
2015-02-05T11:57:48.417
6003
2015-02-05T11:57:48.417
4313
5993
answer


ARCによるメモリ管理が標準的となった現在では、プロパティとインスタンス変数との間に特に差異はありません。「プロパティとは、インスタンス変数へのアクセサメソッドを提供する糖衣構文でしかない」という認識は概ね正しいです。

しかし、インスタンス変数よりもプロパティを使うべきです。

### 宣言的である

プロパティ宣言は、それがどのような性質を持つのか記述できるという強みがあります。

[code]

    @property(copy) NSNumber *value;
    
[/code]

上記のプロパティは値がコピーして保持されることを宣言しています。

[code]

    @property(strong) NSObject *deprecated DEPRECATED_ATTRIBUTE;
    
[/code]

利用が非推奨となったことを宣言できます。プロパティを利用しているコードには警告が表示されます。

このような表現力はインスタンス変数にはありません。

### 実装を隠蔽できる

インスタンス変数は実装詳細です。対してプロパティはAPIです。

例えばインスタンス変数に対して`nil`を代入する処理を行ったとします。

[code]

    value = nil;
    
[/code]

もしインスタンス変数`value`が`nil`を保持することになんらかの不都合があった場合、どう対処すべきでしょうか？ほとんどの場合、対処できません。

対して、プロパティはメソッドによるアクセスなので、

[code]

    self.value = nil;
    
[/code]

という記述は、アクセサを置き換えることで例えば次のように無害化できます。

[code]

    -(void)setValue:(NSValue *)aValue
    {
      if(aValue){
        _value = aValue;
      }else{
        _value = @0;
    }
    
[/code]

初期化を遅延させるなど、様々な応用が可能です。

### 欠点とそれを補うメリット

プロパティに全く欠点がないわけではありません。必ずアクセサを経由することから、関数呼び出しのオーバーヘッドが発生します。もっとも一般的なアプリケーションの作成では十分に無視できる程度に、コンパイラによる最適化が行われます。

「実装詳細にではなく、インターフェースに対してプログラミングする」という良い習慣が定着するメリットの方が大きいです遥かに大きいです。たとえそれが外部からアクセスされない、閉じた領域であったとしても、記法をプロパティに統一することで可読性が上がります。


CC BY-SA 3.0
2015-02-05T15:00:17.803
6017
2015-02-06T11:03:59.870
2015-02-06T11:03:59.870
5337
5337
5993
answer