[iOS] Objective-C @propertyについて

2012/06/25

こんにちは。きんくまです。
今回はObjective-Cの@propertyについてのまとめです。
ARCは使ってないバージョンです。

公式のリファレンスです。
>> Declared Properties

Obj-Cをはじめた当初はよくわからないながらも何となく使っていたのですが、
いろいろとわかってきたのでまとめておこうと思いました。

@propertyはカタカナに直すとプロパティだから、別言語から来た人(私)は
何か実体のあるもののような気がするのですが、そうではなくて
実際はアクセサメソッド(getter, setter)のことです。

なので、クラス外からアクセスするときに必要に応じて定義するとよいです。
最初私はよくわからず、インスタンス変数に全てプロパティを定義していたのはナイショです。

@propertyを使わないでインスタンス変数にアクセス = KVC

ではまずは@propertyを使わないでインスタンス変数にアクセスしてみましょう。
こんな感じのクラスがあるとします。

@interface Person : NSObject
{
    NSString *_firstName;
    NSString *_lastName;
    int _age;
}
@end

@implementation Person
- (void)dealloc
{
    [_firstName release];
    [_lastName release];
    [super dealloc];
}
@end

これにアクセスするのに、Objective-Cに用意されている KVC(Key-value coding)という仕組みを利用します。

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Person *person1 = [[Person alloc] init];

        [person1 setValue:@"Taro" forKey:@"_firstName"]; //KVC

        NSString *name1 = [person1 valueForKey:@"_firstName"]; //KVC

        NSLog(@"name1 = %@", name1);
        [person1 release];        
    }
    return 0;
}

setValue:forKey で値代入(setter)。 valueForKey で値取得(getter)。することができます。

@propertyを定義

KVCでもアクセスできたのですが、毎回書くには長いです。
なので@propertyを使ってみます。その場合、定義する方は長くなるのですが、使う方は短くなります。

@interface Person : NSObject
{
    NSString *_firstName;
    NSString *_lastName;
    int _age;
}

@property (nonatomic, retain) NSString *firstName;
@property (nonatomic, retain) NSString *lastName;
@property (nonatomic, assign) int age;

@end

@implementation Person

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;
@synthesize age = _age;

- (void)dealloc
{
    [_firstName release];
    [_lastName release];
    [super dealloc];
}
@end

@interfaceのクラス定義のところで@propertyを書く。
@implementationのクラス実装のところで@synthesizeを書く。
というふうにやります。

@synthesize

実装ファイルのところで@synthesizeをこう書きました。

@synthesize firstName = _firstName;

私の場合はインスタンス変数とプロパティを明確に区別するために

・インスタンス変数は 「_」アンダースコアを変数名の最初につける
・プロパティには「_」をつけない

とそれぞれ別の名前で書いているので、プロパティとインスタンス変数をひもづけるために上の書き方になります。

もし、インスタンス変数とプロパティが同じ名前だったら

@synthesize firstName;

とするだけでよいです。

Attributes 属性

@propertyの後にあるnonatomic, retain, assignというのがあります。
これは補助情報というか属性というかそんなものです。

私の覚え方としてはこんな感じです。

Attributes 説明
nonatomic スレッド使わないときはこっちを使う
atomic スレッド使うときはこっちを使う。(使ったことないです、、。)
retain setterのとき、代入する対象がNSObjectの子供だったらこっち
assign setterのとき、代入する対象がプリミティブ(int, float, charとかNSObjectの子供じゃない)だったらこっち
readonly 読み込み専用

@propertyを使ってアクセス

「.」ドット を使って書くことができます。KVCよりもすっきりかけました。

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        Person *person1 = [[Person alloc] init];
        person1.firstName = @"Taro";
        person1.lastName = @"Yamada";
        person1.age = 45;
        NSLog(@"%@ %@ is age %d", person1.firstName, person1.lastName, person1.age);
        [person1 release];
        
    }
    return 0;
}

@synthesizeの中身

@synthesizeは実際にどういうことをやるものなのかというと、
コンパイラが後から自動で実際のメソッドを付け足してくれるものです。

こちらで詳しい解説されてます。
>> Objective-Cの @property と @synthesize の組み合わせが何をやっているのかを解説 – 強火で進め

今回の場合だと実装部分にこんなのが足されます。
getterはプロパティと同じ名前の、setterは「set+プロパティ名」のメソッドになります。

- (NSString *)firstName
{
    return _firstName;
}

- (void)setFirstName:(NSString *)firstName
{
    [_firstName release];
    _firstName = [firstName retain];
}

- (NSString *)lastName
{
    return _lastName;
}

- (void)setLastName:(NSString *)lastName
{
    [_lastName release];
    _lastName = [lastName retain];
}

- (int)age
{
    return _age;
}

- (void)setAge:(int)age
{
    _age = age;
}

@propertyはメソッドなので、必ずインスタンス変数に1対1対応していなくてもよい

@propertyはメソッドなので、必ずインスタンス変数に1対1対応していなくてもよいです。
例えば、今回の例に fullName をつけたしてみるとこうなります。


#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    NSString *_firstName;
    NSString *_lastName;
    int _age;
}

@property (nonatomic, retain) NSString *firstName;
@property (nonatomic, retain) NSString *lastName;
@property (nonatomic, readonly) NSString *fullName;  //追加
@property (nonatomic, assign) int age;

@end

@implementation Person

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;
@synthesize age = _age;
@synthesize fullName; //追加

- (void)dealloc
{
    [_firstName release];
    [_lastName release];
    [super dealloc];
}

 //追加
- (NSString *)fullName
{
    return [NSString stringWithFormat:@"%@ %@", _firstName, _lastName];
}

@end

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        Person *person1 = [[Person alloc] init];
        person1.firstName = @"Taro";
        person1.lastName = @"Yamada";
        NSLog(@"fullName is %@", person1.fullName);  //追加
        [person1 release];
        
    }
    return 0;
}
LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る