連載
» 2014年04月09日 18時00分 公開

iOS SDKで始めるObjective-C入門(7):Objective-Cのクラスやプロパティ、特徴的なメソッドの使い方 (2/3)

[平井祐樹,クラスメソッド]

プロパティ

 前回の記事で、Personクラスに名前と年齢を表すインスタンス変数(メンバー変数)とそれらを取得・設定するメソッドを定義しましたね。

#import <Foundation/Foundation.h>
@interface Person : NSObject
{
    // 名前
    NSString *_name;
    
    // 年齢
    NSInteger _age;
}
// 名前を取得する
- (NSString *)name;
// 名前を設定する
- (void)setName:(NSString *)name;
 
// 年齢を取得する
- (NSInteger)age;
// 年齢を設定する
- (void)setAge:(NSInteger)age;
@end
Person.h
#import "Person.h"
@implementation Person
// 名前を取得する
- (NSString *)name
{
    return _name;
}
// 名前を設定する
- (void)setName:(NSString *)name
{
    _name = name;
}
// 年齢を取得する
- (NSInteger)age
{
    return _age;
}
// 年齢を設定する
- (void)setAge:(NSInteger)age
{
    _age = age;
}
@end
Person.m

ゲッター、セッター、アクセサー(メソッド)

 このとき、インスタンス変数から値を取り出して返すメソッドを「ゲッター(Getter)」、インスタンス変数に値を代入するメソッドを「セッター(Setter)」と言います。そして、これらのメソッドをまとめて「アクセサー(メソッド)」とも呼びます。

 例えば、「- (NSString *)name」メソッドはインスタンス変数「_name」のゲッター、「- (void)setName:(NSString *)」メソッドはインスタンス変数「_name」のセッターとなります。

 このように、インスタンス変数には、アクセサーを介して値の取得や設定を行うことが一般的ですが、これらの定義を毎回書くのは面倒ですよね。

 Objective-Cでは、インスタンス変数とアクセサーをまとめて自動生成する機能があります。

 それがプロパティ(@property)です。

プロパティの使い方

 プロパティを使用するにはプロパティを宣言する必要があります。プロパティの宣言は以下のように書きます。

@property (オプション) 型 プロパティ名;

 @interface@endと異なり、文末に「;(セミコロン)」が必要です。オプションについては後で解説しますので、今は気にしないでください。

 プロパティを利用して、Person.hとPerson.mを書き換えると、以下のようになります。

#import <Foundation/Foundation.h>
@interface Person : NSObject
// 名前
@property (nonatomic) NSString *name;
// 年齢
@property (nonatomic) NSInteger age;
@end
Person.h
#import "Person.h"
@implementation Person
@end
Person.m

 だいぶスッキリしましたね。特に実装ファイルはほとんど何もなくなりました。

 このとき、インスタンス変数はプロパティ名の頭に「アンダースコア(_)」が付与されたものが生成されます(例:「_name」「_age」)。

 ゲッターメソッドは、メソッド名にそのままプロパティ名が入ります(例:「- (NSString *)name」「- (NSInteger)age」)。

 セッターメソッドは、プロパティ名の頭にsetが付与され、プロパティ名の頭文字が大文字になります(例:「- (void)setName:」「- (void)setAge:」)。

プロパティへのアクセス

 定義したプロパティへアクセスするには、ドット(.)演算子を使用します。ViewController.m を以下のように変更して実行してみましょう。

#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // Personクラスのインスタンスを生成する
    Person *aPerson = [Person new];
    // nameに値を設定する
    aPerson.name = @"山田太郎";
    
    // nameから値を取得する
    NSString *aName = aPerson.name;
    
    NSLog(@"aName : %@", aName);
}
@end
実行例1

 非常に直感的に書けるようになりましたね。

アクセサーを自分で定義する

 また、セッターとゲッターは自分で定義することもできます。試しに、Person.m を以下のように変更してみましょう。

#import "Person.h"
@implementation Person
- (NSString *)name
{
    return [NSString stringWithFormat:@"%@ 様", _name];
}
@end
Person.m

 これで実行すると、以下のように表示され、自分で定義したゲッターが実行されていることが分かります。また、内部的に「_name」という名前のインスタンス変数が生成されていることも確認できます。

実行例2

プロパティのオプション

 後回しにしたプロパティのオプションについて解説します。プロパティで指定できるオプションには、以下のものがあります。

項目 オプション 意味
所有属性 strong オブジェクト型のプロパティで指定可能。オブジェクトを強い参照で保持する。勝手にメモリから解放されてしまわないようにする
weak オブジェクト型のプロパティで指定可能。オブジェクトを弱い参照で保持する。メモリから解放されてしまう場合がある。その場合はnilが代入される。
copy オブジェクト型のプロパティで指定可能。オブジェクトを強い参照で保持することはstrongと同様だが、保持するインスタンスは受け取ったインスタンスをコピーしたものになる
assign NSIntegerやBOOLなどプリミティブな型のプロパティに指定
スレッドセーフ atomic プロパティをスレッドセーフ(複数のスレッドが同時並行的に実行しても問題が発生しないこと)にする
nonatomic スレッドセーフにしない
アクセス制御 readonly 読み取り専用にする
readwrite 読み書き可能にする
アクセサー名の指定 getter= ゲッターの名前を自分で指定
setter= セッターの名前を自分で指定

 所有属性については、NSStringやNSArrayなどの既存のクラス、または独自に定義したクラスなどのオブジェクト型の場合はstrongが、それ以外の型の場合はassignがデフォルトで設定されるため、省略できます。

 それ以外のオプションについては、スレッドセーフに関するオプションを省略した場合はatomicが、アクセス制御に関するオプションを省略した場合は、readwriteがデフォルトで設定されます。

 そのため、先ほどPerson.hに記載した宣言は以下のものと同様です。

@property (strong, nonatomic, readwrite) NSString *name;
@property (assign, nonatomic, readwrite) NSInteger age;

 明示的にnonatomicを指定しているのは、atomicを指定してもパフォーマンスを悪化させるだけで、ほとんどの場合にメリットが無いためです。ですので、よほどのことが無い限りはnonatomicを指定しておきましょう。

Copyright © ITmedia, Inc. All Rights Reserved.

編集部からのお知らせ

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。