Objective-cの「インスタンス変数」と「プロパティ」に違いはありますか?


82

Objective-cの「インスタンス変数」と「プロパティ」に違いはありますか?

これについてはよくわかりません。「プロパティ」はアクセサメソッドを持つインスタンス変数だと思いますが、間違っていると思うかもしれません。

回答:


84

プロパティは、より抽象的な概念です。インスタンス変数は、構造体のスロットのように、文字通り単なるストレージスロットです。通常、他のオブジェクトがそれらに直接アクセスすることは想定されていません。一方、プロパティは、アクセスできるオブジェクトの属性です(あいまいに聞こえ、アクセスできるはずです)。通常、プロパティはインスタンス変数を返すか設定しますが、複数のデータを使用することも、まったく使用しないこともあります。例えば:

@interface Person : NSObject {
    NSString *name;
}

    @property(copy) NSString *name;
    @property(copy) NSString *firstName;
    @property(copy) NSString *lastName;
@end

@implementation Person
    @synthesize name;

    - (NSString *)firstName {
        [[name componentsSeparatedByString:@" "] objectAtIndex:0];
    }
    - (NSString *)lastName {
        [[name componentsSeparatedByString:@" "] lastObject];
    }
    - (NSString *)setFirstName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
    - (NSString *)setLastName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
@end

(注:上記のコードは、名前がすでに存在し、少なくとも2つのコンポーネント(たとえば、「Gates」だけでなく「Bill Gates」)があると想定しているという点でバグがあります。これらの想定を修正すると、コードの実際のポイントになると感じました。あまり明確ではないので、ここで指摘しているだけなので、誰も無邪気にそれらの間違いを繰り返すことはありません。)


4
私がプロパティを表示している方法は、外部オブジェクトのインスタンス変数へのアクセスを提供/制限する手段です。他の言語のパブリック/プライベートの概念のようなものですか?
典型的な

「通常、他のオブジェクトがそれらに直接アクセスすることは想定されていません」これはどういう意味ですか?また、あなたの答えは現代のObjective-cで更新されていますか?
ハニー

1
@Honey彼はカプセル化の概念に言及し、ベストプラクティスに従っていると思います。他のオブジェクトは、ivarに直接アクセスしたり変更したりできないようにする必要があります。プロパティを介してivarアクセス​​を制御することにより、ivarに影響を与える可能性がある前にそれらの呼び出しをインターセプトできます。詳細については、こちらを参照してください:en.wikipedia.org/wiki/Encapsulation_
computer_programming

33

プロパティは、追加の便利な機能と構文を備えた、ある値のゲッター/セッターを実装するための使いやすい方法です。プロパティはインスタンス変数でバックアップできますが、getter / setterを定義して、もう少し動的な処理を行うこともできます。たとえば、一部のメンバーの値を返すのではなく、結果を動的に作成する文字列にlowerCaseプロパティを定義できます。変数。

次に例を示します。

// === In your .h ===

@interface MyObject {
    NSString *propertyName;

}

// ...

@property (nonatomic, retain) NSString *propertyName;

// === In your .m @implementation ===

@synthesize propertyName /* = otherVarName */;

ザ・ @property行は、propertyNameタイプと呼ばれるプロパティを定義しますNSString *。これは、次の構文を使用して取得/設定できます。

myObject.propertyName = @"Hello World!";
NSLog("Value: %@", myObject.propertyName);

あなたがあなたに割り当てたり、myObject.propertyNameあなたから読んだりするとき、あなたは本当にオブジェクトのsetter / getterメソッドを呼び出しています。

この@synthesize行は、値を格納するためにプロパティと同じ名前のメンバー変数をotherVarName使用して(またはコメントで構文を使用する場合)、これらのゲッター/セッターを生成するようにコンパイラーに指示します。

加えて@synthesize、独自の定義を行うことで、ゲッター/セッターの1つをオーバーライドできます。これらのメソッドの命名規則は次のとおりです。setPropertyName:、セッター用であり、propertyName(またはgetPropertyName、標準ではなく)ゲッター用です。もう1つは引き続き生成されます。

あなたの@property行では、スレッドセーフやメモリ管理などを自動化できるプロパティの親にいくつかの属性を定義できます。デフォルトでは、プロパティはアトミックであり、コンパイラがラップすることを意味します@synthesiz、並行性の問題を防ぐために、適切なロックでget / set呼び出しをします。nonatomicこれを無効にする属性を指定できます(たとえば、iPhoneではほとんどのプロパティをデフォルトにしますnonatomic)。

@synthesizedセッターのメモリ管理を制御する3つの属性値があります。1つ目は、プロパティの古い値と新しい値にretain自動的に送信releaseするものretainです。これはとても便利です。

2つ目はcopy、渡された値を保持するのではなく、それらのコピーを作成する方法です。copy呼び出し元がNSMutableStringを渡して、自分の下から変更する可能性があるため、NSStringに使用することをお勧めします。copyあなただけがアクセスできる入力の新しいコピーを作成します。

3つ目はassign、古いオブジェクトまたは新しいオブジェクトでretain / releaseを呼び出さずにストレートポインタ割り当てを行う方法です。

最後に、readonly属性を使用して、プロパティのセッターを無効にすることもできます。


1
インスタンス変数とプロパティ(例:propertyName)を宣言することに何か利点はありますか?同じ変数のプロパティを宣言する場合、インターフェイス内の宣言は必要ありませんよね?私が欠けている何かがありますしない限り、これは実際に、コードの行に保存されます。..
whyoz

6

私はインターフェース部分のプロパティを使用します-オブジェクトが他のオブジェクトとインターフェースし、インスタンス変数がクラス内で必要なものです-誰もがそれらを見て操作することになっています。


3

デフォルトでは、読み取り/書き込みプロパティはインスタンス変数によってサポートされ、インスタンス変数はコンパイラによって自動的に合成されます。

インスタンス変数は、存在し、オブジェクトの存続期間中その値を保持する変数です。インスタンス変数に使用されるメモリは、オブジェクトが最初に作成されたときに(allocを介して)割り当てられ、オブジェクトの割り当てが解除されたときに解放されます。

特に指定しない限り、合成されたインスタンス変数はプロパティと同じ名前ですが、アンダースコアプレフィックスが付いています。たとえば、firstNameというプロパティの場合、合成されたインスタンス変数は_firstNameと呼ばれます。


2

以前は、プロパティをパブリックに使用し、ivarをプライベートに使用していましたが、数年前から、プロパティを定義@implementationしてプライベートに使用することもできます。ただし、入力する文字が少なく、この記事によると実行速度が速いため、可能な場合はivarを使用します。プロパティは「重い」ことを意味するため、理にかなっています。生成されたゲッター/セッターまたは手動で作成されたゲッター/セッターのいずれかからアクセスされることになっています。

ただし、Appleの最近のコードでは、ivarは使用されなくなりました。それはより多くのようなものですので、私は推測するobjcのではなくC/C++、それに加えてとプロパティを使用する方が簡単ですassignnullableなど、


私の推測では、Appleのプロパティの使用法は@implementationSwiftとの類似点を示したいと考えています。それでも、自分のクラスの単純なフィールドを検索するために、仮想関数呼び出しを無駄にしないように変数をバッキングすることも好みます(これは、プロパティにアクセスしたときに発生します)。
レオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.