イニシャライザ
- Objectiv-cにはコンストラクターがありません。
- その代わり、オブジェクトをインスタンス化した場合は、直後に init メッセージを送信しなければなりません。 この作業は自動的なものではなく、明示的にメッセージから呼び出さなければなりません。
- 一般的には次のように記述されています。[[クラス名 alloc] init]。initメソッドの戻り値は、初期化を済ませたクラスインスタンスです。
- init メソッドをオーバーライドすることで初期化処理を追加することができます。init メソッドをオーバーライドする場合は、スパークラスの init メソッドを呼び出す必要がある。
- init メソッドは引数を受け取ることができません。引数が必要な場合は init メソッドとは異なるイニシャライザを作成する。指定イニシャライザと呼びます。指定イニシャライザは、習慣的に initWith から開始する引数を受けるメソッドとなります。
- サブクラスでスーパークラスの指定イニシャライザをオーバーライドした場合、必ずスーパークラスの指定イニシャライザを呼び出す必要があります。1つのクラスが複数のイニシャライザを持つ場合は、その中の1つのイニシャライザだけが上位クラスの「init」を呼び出すようにして、ほかのイニシャライザは、「init」を呼んだ初期化メソッドを呼ぶようにする。
- コンビニエンスコンストラクタ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
@interface TestClass : NSObject{ } //指定イニシャライザ - (id)initWithTitle:(int)pintA TilteName:(NSString *)pstrB; //指定イニシャライザ - (id)initWithTitle:(int)pintA; @end @implementation TestClass //インスタンス変数 int mintTitleCode; NSString *mstrTilteName; // 指定イニシャライザ(引数2つ) - (id)initWithTitle:(int)pintA TilteName:(NSString *)pstrB { if(self = [super init]){ mintTitleCode = pintA; mstrTilteName = pstrB; } return self; } // 指定イニシャライザ(引数1つ) - (id)initWithTitle:(int)pintA { return [self initWithTitle:pintA TilteName:@"AAA"]; } // スーパークラスのイニシャライザのオーバーライド - (id)init { return [self initWithTitle:999 TilteName:@"AAA"]; } @end |
インスタンス変数
- インスタンスごとに違った値を保持する変数。通常クラス自身の外からアクセスされることはない
- 以前は.hの@interfaceに記述していたが、いまは.mの@implementationに書くのが主流
メソッド
- 引数が3つの場合の定義 - (戻り値の型)メッセージ式のメソッド名:(引数の型)引数1 ラベル:(引数の型)引数2 ラベル:(引数の型)引数3
- ラベルは省略可能
- 第一引数にラベルを付与することはできない
- 引数はラベルの有無に関わらず,定義した順に指定しなければならない
- 第一引数の前にあるのは 「メソッド名」 ではなく 「第一引数の説明」 だと解釈する
- 戻り値の前に「マイナス(-)」がある場合は、インスタンスメソッドであることを示しています。「プラス(+)」を指定すると、クラスメソッドになります。
- ラベルはメソッド名の一部。メッセージ式のメソッド名と引数のラベルを全て繋いだものが、Objective-Cが認識するメソッド名となる。
1 2 3 4 |
- (NSString *)InstanceMethod:(int)pintA pstrXXX:(NSString *)pstrB; - (NSString *)InstanceMethod:(int)pintA pstrYYY:(NSString *)pstrB; ※メッセージ式のメソッド名(instanceMethod)が同じでも、ラベルが異なれば、メソッド名も異なる。 |
プロパティ
- インスタンス変数にアクセス指定子を付けて宣言することで、インスタンス自身ではないオブジェクトからもアクセスできるようになる。
- .hで宣言する際、@synthesize propertyName; と記述。特に指定がなければ、値の設定が可能なプロパティのインスタンス変数は 「_propertyName」という名前になる。Objective-Cでプロパティを宣言すると、暗黙的にインスタンス変数が自動生成されます。
- インスタンス変数として別名を指定したい場合は、.mの@implementationに @synthesize propertyName = instanceVariableName; のように=に続けて指定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// .h @interface TestClass : NSObject{ } @property NSString * testProperty1; //プロパティ宣言 @property NSString * testProperty2; //プロパティ宣言 @end //.m @implementation TestClass NSString *mstrTestProperty2; //インスタンス変数 @synthesize testProperty2 = mstrTestProperty2; //インスタンス外部からアクセッサメソッドを提供 //プロパティのテストメソッド - (void)PropertyTestMethod{ NSLog(@"%@", _testProperty1); NSLog(@"%@", mstrTestProperty2); } @end //プロパティを使う TestClass *tcObj = [[TestClass alloc] init]; tcObj.testProperty1 = @"あああ"; tcObj.testProperty2 = @"いいい"; [tcObj PropertyTestMethod]; |
プロパティ属性
所有属性 | strong |
オーナーシップを持つ(参照カウントがincrementされる) オブジェクト型のプロパティで指定可能。オブジェクトを強い参照で保持する。勝手にメモリから解放されてしまわないようにする |
weak |
オーナーシップを持たない(参照カウントがincrementされない)。オブジェクトが解放されるとnilを返す様になる。 オブジェクト型のプロパティで指定可能。オブジェクトを弱い参照で保持する。メモリから解放されてしまう場合がある。その場合はnilが代入される。 |
|
copy |
コピーに対してオーナーシップを持つ(setterに渡されたオブジェクトのコピーを作るため、元のオブジェクトとは違うオブジェクトを持つ) オブジェクト型のプロパティで指定可能。オブジェクトを強い参照で保持することはstrongと同様だが、保持するインスタンスは受け取ったインスタンスをコピーしたものになる。 |
|
unsafe_unretained | retain(strongと同じ意味)せずに参照を持つ。weakが無い時代に使われた。今となっては歴史的経緯で残ってるだけのやつで、使っちゃダメ。 | |
assign |
intやBOOLみたいなプリミティブな値を保持する際に使われる。単純な代入を意味していて、オブジェクトに対して指定すると単なる参照の代入なので要はunsafe_unretainedとかと同じ。これもオブジェクトに対しては使っちゃダメ。 NSIntegerやBOOLなどプリミティブな型のプロパティに指定 |
|
retain | strongと同じ。完全に歴史的経緯で残ってるだけなのでやっぱり使っちゃダメ。 | |
スレッドセーフ(アトミック) | atomic |
プロパティをスレッドセーフにする(複数のスレッドが同時並行的に実行しても問題が発生しないこと)。プロパティに複数の処理が同時にアクセスしても”lock”、”unlock”機能が働き、一つずつしか処理されない。getter と setter が排他的に実行されるようになり、値の書き込みに複数のメモリ操作命令が必要な型(構造体など)が中間状態で読み出されることがなくなる |
aonatomic | スレッドセーフにしない。nonatomicを指定すると「このアクセサメソッドは同時に実行されることはないから、ロックしなくていい」ということをコンパイラに示していることになる。 | |
アクセス制御 | readonly | 読み取り専用にする |
readwrite | 読み書き可能にする | |
アクセサー名の指定 | getter= | ゲッターの名前を自分で指定 |
setter= | セッターの名前を自分で指定 |
strong/weekの使い分け
atomic/nonatomicの使い分け
- できる限り nonatomic を指定する
- 参照型: メモリアドレスのみの書き込みなので、常にnonatomicでよい
- プリミティブ型: int, BOOL等ワンステップでの書き込みが可能: 常にnonatomicでよい
- プリミティブ型: 単一のスレッドからしかアクセスされない: 設計に気をつけつつnonatomic推奨
- プリミティブ型: 複数のスレッドからのアクセスがあり、long,構造体などサイズの大きい値: atomic推奨
クラス拡張
- 実装ファイル(.mファイル)の方で@interfaceを宣言する。
- ヘッダに公開したくないプライベートメソッドやインスタンス変数を隠蔽する記述が可能になる。
- C++でいうところのpimplイディオム的なものだと考える。
変数のスコープ定義について
- Objective-Cではアクセス権に関するコンパイラディレクティブ(@〜)を使う事でインスタンス変数のアクセス権をコントロールする
- @private クラス外部からはアクセスできません。完全に隠蔽された状態です。インスタンス変数をクラス内だけで利用する場合に指定します。
- @protected クラス内部およびサブクラス内であればアクセスできます。デフォルトではこれが指定されています。
- @public クラス外部からも自由にアクセスできます。完全に公開された状態です。
1 2 3 4 5 |
@interface クラス { @public public変数 @protected protected変数 @private private変数 } |
インスタンス変数の宣言場所
- ヘッダファイル(.hファイル)内の @interface に記述。.hファイル内に隠蔽したいインスタンス情報が記述されるので、推奨していない記述方法。
- 実装ファイル(.mファイル)内の @interface に記述(クラス拡張)。StoryboardとOutletの接続を行う場合に記述する方法。実装ファイル(.mファイル)内の @:implementation でも可能だが、@:implementation に記述すると、Storyboardの当該箇所にこのインスタンス名がすぐには表示されない問題がある。そのため、実装ファイル(.mファイル)内の @interface に記述する。
- 実装ファイル(.mファイル)内の @:implementation に記述。隠蔽したいインスタンス変数の宣言を記述する。
プロパティとメソッドのスコープ
- Objective-Cでは、他のクラスからプロパティへのアクセスやメソッドの呼び出しを行えるようにするために、それらの宣言をヘッダーファイルに記載します。
- ヘッダーファイルに宣言されたプロパティやメソッドは全て他のクラスから参照できる状態(Public)されてしまいます。
- Objective-Cにはプロパティやメソッドを非公開にするための言語的機能がありません。
- プライベートで宣言したい場合は、クラス拡張機能で実装ファイルで宣言を行い、疑似的に非公開(Private)にすることが可能です。
参照させて頂いたページ
Objective-Cでの「プロパティ」「インスタンス変数」「ローカル変数」の違い
インスタンス変数と@propertyと@synthesizeを理解する
Objective-Cでは、インスタンス変数をどこに宣言するのが正しいのか?
Objective-Cのクラスやプロパティ、特徴的なメソッドの使い方
Objective-Cのクラスやプロパティ、特徴的なメソッドの使い方 (3/3)
1 |
//当該メソッド実行時に待たせるor待たせないを選択可能とさせる。 |
1 |
//当該メソッド実行時に待たせるor待たせないを選択可能とさせる。 |
1 |
//当該メソッド実行時に待たせるor待たせないを選択可能とさせる。 |
1 |
//当該メソッド実行時に待たせるor待たせないを選択可能とさせる。 |
1 |
//当該メソッド実行時に待たせるor待たせないを選択可能とさせる。 |
1 |
//当該メソッド実行時に待たせるor待たせないを選択可能とさせる。 |