Start Developing iOS Apps Today(sup.2)〜Objective-Cコードの記述

2012. 12. 01
貴方がiOSまたはMac OS Xのどちらかでプログラムをしていなかった場合、主要なプログラミング言語であるObjective-Cに精通する必要があります。
Objective-Cは難しい言語ではなく、一度しばらく使用してみると、その優雅さを理解できるでしょう。
Objective-C言語は、洗練されたオブジェクト指向プログラミングを可能にします。
Objective-C言語は、標準ANSI Cプログラミング言語に、クラスやメソッドを定義する構文を規定したものです。
またクラスや任意のクラスが採用できるインターフェイスの動的拡張を推奨しています。

ANSI Cに精通している場合、以下の情報はObjective-Cの基本的な構文を学ぶのに役立ちます。
また他のオブジェクト指向言語でプログラミングしていた場合、カプセル化や継承、多態性といった因習的なオブジェクト指向の概念の全てが、Objective-Cで表現されているのを多く見つけることができるでしょう。
ANSI Cに精通していない場合、この記事を読もうとする前に、少なくともC言語の概要を読んでおくことをお勧めします。

Objective-Cプログラミング言語』では、Objective-C言語の完全な説明がされています。



●Objective-CはC言語のスーパーセット

Objective-C言語は、オブジェクトのメソッドの呼び出しや、クラスの動的拡張、特定の問題に対処するように適応されたプログラミングインターフェイスの生成をするための、クラスやメソッドを定義する構文を指定します。
Objective-CはCプログラミング言語のスーパーセットで、Cと同じ基本的な構文をサポートします。
(int、floatなどの)原始的な型、構造体、関数、ポインタ、if...elseやfor文などの制御フロー構成といった、一般的な要素の全てを持っています。
また、stdlib.hやstdio.hなどで宣言されている標準Cライブラリのルーチンへのアクセスも持っています。

Objective-CはANSI Cの機能に以下の構文が追加されます。
  • 新しいクラスの定義
  • クラスメソッドとインスタンスメソッド
  • メソッドの呼び出し(メッセージングと呼ばれます)
  • プロパティ(とそれらからのアクセサメソッドの自動合成)の宣言
  • 静的および動的型付け
  • ブロック(常時実行可能な、コードのカプセル化セグメント)
  • プロトコルやカテゴリなどの、基本的な言語の拡張
現在、このようなObjective-Cの側面を知らなくても心配しないでください。
この記事の残りの部分を読み進めることによって、これらについて学びます。
貴方がオブジェクト指向の概念に不慣れな手続き型プログラマの場合、最初は基本的にオブジェクトに関連付けられた機能を持つ構造として考えるとよいでしょう。
ただし、この見解は特にランタイム実装において実際とは乖離しています。

さらに他のオブジェクト指向言語に見られるほとんどの抽象概念やメカニズムを提供するObjective-Cは、非常に動的な言語で、そのダイナミズムが最大の利点です。
アプリの動作はアプリのビルド時に固定されるのではなく、実行時に(つまりランタイムで)動的に決定することができます。
したがってObjective-Cのダイナミズムはコンパイルやリンク時に課せられる制約からプログラムを解放し、代わりにユーザの制御時にランタイムでシンボルの解決をする責任を負います。



●クラスとオブジェクト

ほとんどのオブジェクト指向言語と同様に、Objective-Cのクラスはデータのカプセル化をサポートし、そのデータを操作するアクションを定義します。
オブジェクトはクラスの実行時のインスタンスです。
それにはクラスによって宣言されたインスタンス変数のコピーと、クラスのメソッドへのポインタが自身のメモリ内に含まれています。
オブジェクトは割り当て(allocation)と初期化(initialization)という2つの工程を呼び出して生成します。

Objective-Cでのクラスの指定には、インターフェイスと実装といった2つの部分を必要とします。
インターフェイス部分は、クラス宣言とクラスの公開インターフェイスの定義が含まれています。
Cコードと同様に、貴方のコードではソースファイルでの実装の詳細から公開宣言を分離するために、ヘッダファイルで定義します。
(プログラムインターフェイスの一部の場合、実装ファイル内で他の宣言を記述することができますが、プライベートであることを意味します。)
これらのファイルは下表に示すファイル名の拡張子を持っています。

拡張子ソースタイプ
.hヘッダファイル。
ヘッダファイルには、クラス、型、関数、および定数の宣言が含まれています。
.m実装ファイル。
この拡張子のファイルは、Objective-CとCコードの両方を含めることができます。
時々ソースファイルと呼ばれます。
.mm実装ファイル。
この拡張子のファイルは、Objective-CとCコードに加え、C++コードを含めることができます。
実際にはObjective-CコードからC++のクラスまたは機能を明示する場合のみ、この拡張子を
使用します。

ソースコードにヘッダファイルをインクルードしたい場合は、ヘッダファイルまたはソースファイルの最初の行の1つとして、インポートのディレクティブ(#import)を指定します。
#importディレクティブは同じファイルを複数回インクルードしないことを確認すること以外は、Cの#includeディレクティブと同様です。
フレームワークのヘッダファイルのほとんど、または全てをインポートしたい場合は、フレームワークと同じ名前を持つフレームワークのアンブレラヘッダファイルをインポートします。
(仮想の)Gizmoフレームワークのヘッダファイルをインポートする構文は以下の通りです。

#import <Gizmo/Gizmo.h>

基本(またはルート)クラスであるNSObjectから継承されるMyClassと呼ばれるクラスの宣言をする場合の構文を下図に示します。
(ルートクラスは、全てのクラスが直接または間接的に継承しているクラスです。)
クラスの宣言は@interfaceコンパイラディレクティブで始まり、@endディレクティブで終わります。
クラス名(と区切りのコロン)の後が、親クラスの名前です。
Objective-Cでは、クラスの親は1つだけ持つことができます。

class_decl_2x.png

プロパティとメソッドの宣言は、@interfaceと@endディレクティブの間に記述します。
これらの宣言は、クラスのパブリックインターフェイスを形成します。
(宣言済みプロパティは『宣言済みプロパティとアクセサメソッド』で説明しています。)
セミコロンは、各プロパティやメソッドの宣言の終端を示しています。
クラスがカスタム関数、定数、またはパブリックインターフェイスに関連付けられたデータ型を持っている場合は、@interface...@endブロックの外側で宣言します。

クラス実装の構文も類似しています。
@implementation(の後にクラス名が続く)コンパイラディレクティブで始まり、@endディレクティブで終わります。
その間にメソッドを実装します。
(関数の実装は、@implementation...@endブロックの外側で行う必要があります。)
実装では、常にコードの最初の行の1つとしてインターフェイスファイルをインポートする必要があります。

#import "MyClass.h"

@implementation MyClass

- (id)initWithString:(NSString *)aName
{
    // code goes here
}

+ (MyClass *)myClassWithString:(NSString *)aName
{
    // code goes here
}

@end

Objective-Cはオブジェクトを格納している変数の動的型付けをサポートしていますが、静的型付けもサポートしています。
静的に型付けられた変数には、変数の型宣言でのクラス名が含まれています。
動的に型付けられた変数は、代わりにオブジェクトの型idが使用されます。
特定の状況で使用される変数は、動的型付けされていることに気付くでしょう。
例えば(格納されたオブジェクトの正確な型が不明な)配列のようなコレクションオブジェクトは、動的型付けされた変数を使用する場合があります。
このような変数は途方もない柔軟性と、Objective-Cプログラムのより大きなダイナミズムを可能にします。

静的および動的な型の変数宣言の例を以下に示します。

MyClass *myObject1;    // Static typing
id             myObject2;    // Dynamic typing
NSString *userName;    // From Your First iOS App (static typing)

最初の宣言にあるアスタリスク『*』に注目してください。
Objective-Cでは、オブジェクトの参照は常にポインタである必要があります。
この要件は、貴方が完全な意味を把握していない場合は気にする必要はありません。
Objective-Cのプログラミングを開始するために、ポインタの専門家になる必要は無いからです。
静的に型付けされたオブジェクト宣言の変数名の前にはアスタリスクを付けることは忘れないでください。
id型はポインタを意味します。



●メソッドとメッセージング

貴方がオブジェクト指向プログラミングに不慣れな場合、メソッドは特定のオブジェクトにスコープが設定された関数と考えると良いでしょう。
オブジェクトへのメッセージの送信(またはメッセージング)は、オブジェクトのメソッドの呼び出しです。
Objective-Cにはインスタンスメソッドとクラスメソッドの2種類があります。
  • インスタンスメソッドは、クラスの特定のインスタンスにスコープが設定されて実行するメソッドです。
    すなわち、インスタンスメソッドを呼び出す前にクラスのインスタンスを最初に生成する必要があります。
    インスタンスメソッドはメソッドの最も一般的なタイプです。

  • クラスメソッドは、メソッドのクラスにスコープが設定されて実行するメソッドです。
    オブジェクトのインスタンスがメッセージのレシーバである必要はありません。
メソッドの宣言は、メソッドの型識別子、戻り値の型、1つ以上のシグネチャキーワード、および引数の型と名前という情報で構成されています。
insertObject:atIndex:インスタンスメソッドの宣言は下図のようになります。

method_decl_2x.png

インスタンスメソッドは宣言の前にマイナス記号『-』を付け、クラスメソッドの場合はプラス記号『+』になります。
クラスメソッドに関しては、後述する『クラスメソッド』でより詳細に説明します。

メソッドの実際の名前(insertObject:atIndex:)は、全てのシグネチャキーワードをコロン文字で連結したものです。
コロン文字は引数が存在することを宣言します。
上記の例では、メソッドは2つの引数を持ちます。
メソッドが引数を持たない場合、最初(にして唯一)のシグネチャキーワードの後のコロンを省略します。

メソッドを呼び出したい場合、メソッドを実装するオブジェクトにメッセージを送信することで行います。
(『メソッドの呼び出し』の別称として一般的に『メッセージを送信』という語句を使用していますが、Objective-Cランタイムでは実際に送信しています。)
メッセージは、メソッドが必要とする(型に正確に一致する)引数情報を伴うメソッド名です。
オブジェクトに送信される全てのメッセージは動的にディスパッチされるため、Objective-Cクラスの多態性な動作を容易にします。
(ポリモーフィズム(多態性)とは、異なる型のオブジェクトに対して同じメッセージで応答できる能力を意味します。)
呼び出されるメソッドがメッセージを受信したオブジェクトのクラスのスーパークラスによって実装されている場合もあります。

メッセージをディスパッチするには、ランタイムでのメッセージ式が必要です。
メッセージ式は、メッセージ自体を(必要な引数と共に)角括弧([と])で括り、括弧内の左端にはメッセージを受信するオブジェクトを指定します。
例えば、insertObject:atIndex:メッセージをmyArray変数が保持するオブジェクトに送信する場合は、以下の構文を使用します。

[myArray insertObject:anObject atIndex:0];

一時的な結果を格納するために多数のローカル変数を宣言することを避けるために、Objective-Cはメッセージ式のネストを許可しています。
ネストされた各式からの戻り値は他のメッセージの引数、または受信するオブジェクトとして使用されます。
例えば、値を取得するメッセージと、前述の例で使用している変数のいずれかを置き換えることができます。
したがって、myAppObjectと呼ばれる別のオブジェクトがあり、配列オブジェクトにアクセスして配列内にオブジェクトを挿入するためのメソッドを持っている場合、前述の例は下記のように記述することができます。

[[myAppObject theArray] insertObject:[myAppObject objectToInsert] atIndex:0];

Objective-Cはまた、アクセサメソッドを呼び出すためのドット記法の構文を提供します。
アクセサメソッドはオブジェクトの状態を設定または取得し、全てのオブジェクトの重要な特質であるカプセル化の鍵となります。
オブジェクトを隠蔽またはカプセル化し、その状態とその状態にアクセスするための全てのインスタンスに共通するインターフェイスを提示します。
ドット記法の構文を使用すると、前述の例は以下のように書き換えることができます。

[myAppObject.theArray insertObject:myAppObject.objectToInsert atIndex:0];

また、割り当てのためにドット記法の構文を使用することができます。

myAppObject.theArray = aNewArray;

この構文は単純に[myAppObject setTheArray:aNewArray];を別の方法で記述したものです。
ドット記法の式では、動的型付けされたオブジェクト(id型のオブジェクト)への参照に使用することはできません。

貴方は既に『初めてのiOSアプリケーション』において、変数の割り当てにドット構文を使用しています。

self.userName = self.textField.text;


クラスメソッド

前述の例ではクラスのインスタンスにメッセージを送信していましたが、クラス自身にメッセージを送信することもできます。
(クラスはランタイムによって生成されたClass型のオブジェクトです。)
クラスへメッセージングする場合、メソッドはインスタンスメソッドの代わりにクラスメソッドとして定義する必要があります。
クラスメソッドはC++の静的クラスメソッドに似た機能です。

クラスメソッドは多くの場合、クラスの新しいインスタンスを生成するファクトリメソッドとして、またはクラスに関連付けられている共有された情報のいくつかにアクセスするために使用されます。
クラスメソッドを宣言する構文は、メソッドの型識別子のマイナス記号の代わりにプラス記号(+)を使用することを除けば、インスタンスメソッドと同じです。

次の例では、クラスのファクトリメソッドとしてクラスメソッドをどのように使用するかを説明します。
この場合arrayメソッドは、クラスの新しいインスタンスを割り当てて初期化しコードにそれを返す、NSArray(と継承しているNSMutableArray)クラスのクラスメソッドです。

NSMutableArray *myArray = nil;    // nil is essentially the same as NULL

// Create a new array and assign it to the myArray variable.
myArray = [NSMutableArray array];



●宣言済みプロパティとアクセサメソッド

一般的な意味でのプロパティは、オブジェクトによってカプセル化または格納されたいくつかのデータです。
これは名前や色などの属性や、1つ以上の他のオブジェクトへの関係です。
オブジェクトのクラスは、そのオブジェクトのユーザがカプセル化されたプロパティの値を取得または設定するためのインターフェイスを定義します。
これらのアクションを実行するメソッドは、アクセサメソッドと呼ばれます。

アクセサメソッドには2つのタイプがあり、各メソッドは次の命名規則に準拠する必要があります。
『ゲッタ(getter)』アクセサメソッドはプロパティの値を返し、プロパティと同じ名前を持ちます。
『セッタ(setter)』アクセサメソッドはプロパティに新しい値を設定し、プロパティ名の最初の文字が大文字となる、setPropertyName:という形式を持ちます。
適切な名前のアクセサメソッドは、CocoaとCocoa Touchフレームワークのいくつかの技術の重要な要素で、キー値コーディング(KVC)を含め、それらの名前を介して間接的にオブジェクトのプロパティにアクセスするメカニズムです。

Objective-Cはアクセサメソッドの宣言と実装のため、表記上の便宜として宣言済みプロパティを提供します。
初めてのiOSアプリケーション』において貴方はuserNameプロパティを宣言しました。

@property (nonatomic, copy) NSString *userName;

宣言済みプロパティは、クラスで公開される各プロパティのゲッタとセッタメソッドを実装する必要がありません。
代わりに、プロパティ宣言で使用する動作を指定します。
コンパイラは宣言に基づいて、実際のゲッタまたはセッタを生成(または合成)します。
宣言済みプロパティは定型的なコードの記述を減らすことになり、その結果としてエラーの発生し難い、はるかに綺麗なコードを作ることができます。
オブジェクトの状態の項目を取得または設定するには、宣言済みプロパティまたはアクセサメソッドを使用します。

クラスのインターフェイス内には、メソッド宣言を伴うプロパティ宣言を含めます。
クラスのヘッダファイルにはパブリックプロパティを宣言し、ソースファイルのクラス拡張にはプライベートプロパティを宣言します。
(例を含めたクラス拡張の簡単な説明については『プロトコルとカテゴリ』を参照してください。)
デリゲートやビューコントローラなどのコントローラオブジェクトのプロパティは、通常プライベートにする必要があります。

プロパティの基本的な宣言では@propertyコンパイラディレクティブを使用し、型情報やプロパティ名が続きます。
また弱い参照であるか、読み込み専用であるか、アクセサメソッドがどのように動作するかを定義する、カスタムオプションでプロパティを構成することができます。
オプションは、@propertyディレクティブに続く括弧内に記述します。

以下にいくつかのプロパティ宣言のコード行を示します。

@property (copy) MyModelObject *theObject;    // Copy the object during assignment.
@property (readonly) NSView *rootView;           // Declare only a getter method.
@property (weak) id delegate;                            // Declare delegate as a weak reference

宣言済みプロパティはコンパイラが自動的に合成します。
プロパティの合成では、アクセサメソッドだけでなく、プロパティの『裏』でプライベートなインスタンス変数を生成します。
インスタンス変数はプロパティとして同じ名前を持ちますが、アンダースコア接頭辞(_)を持ちます。
貴方のアプリは、オブジェクトの初期化と解放のためのメソッドでのみ、(プロパティの代わりに)インスタンス変数に直接アクセスする必要があります。

インスタンス変数に別の名前を付けたい場合は、プロパティの自動合成を迂回して明示的に合成することができます。
クラスの実装で@synthesizeコンパイラディレクティブを使用し、特別な名前のインスタンス変数と一緒にアクセサメソッドを生成するようにコンパイラに依頼します。
例えば、

@synthesize enabled = _isEnabled;

ちなみにプロパティ宣言の際にアクセサメソッドにカスタム名を指定することができますが、以下のブール型プロパティのゲッタメソッドのように、通常は一般的な形式に準ずるように作成します。

@property (assign, getter=isEnabled) BOOL enabled;    // Assign new value, change name of getter method



●ブロック

ブロックは処理の単位(コードのひとまとまり)をカプセル化したオブジェクトで、いつでも実行することができます。
ブロックは基本的に可搬性を持ち、メソッドや関数の引数として渡すことができる、またはメソッドや関数から返すことができる匿名関数です。
ブロック自体は型付きの引数リストを持ち、推定または宣言された戻り値型を持つ場合もあります。
また、変数にブロックを割り当て、関数と同じように呼び出すこともできます。

カレット(^)はブロックの構文マーカーとして使用されます。
他にも、一般的な引数の構文規則、戻り値、ブロックの本体(つまり実行されるコード)があります。
変数にブロックを割り当てる際の具体的な構文を下図に示します。

blocks_2x.png

関数のようにブロック変数を呼び出すことができます。

int result = myBlock(4)    // result is 28

ブロックはローカルのレキシカルスコープ内のデータを共有します。
このブロックの特性は有用で、メソッドを実装し、そのメソッドがブロックを定義している場合、ブロックはインスタンス変数を含むグローバル変数や関数だけでなく、(スタック変数を含む)メソッドの引数やローカル変数へのアクセスを持ちます。
このアクセスは読み込みのみですが、変数が__block修飾子で宣言されている場合、その値はブロック内で変更することができます。
ブロックを囲むメソッドまたは関数が返されてローカルスコープが破棄された後でも、ローカル変数はブロックへの参照がある間はブロックオブジェクトの一部として保持されます。

メソッドや関数の引数として、ブロックはコールバックとして扱うことができます。
呼び出されると、メソッドまたは関数はいくつかの処理を実行し、適切な瞬間に、追加の情報を要求する、またはプログラム固有の動作を取得するために、(ブロックを介して)呼び出すコードをコールバックします。
ブロックは呼び出し時点でコールバックのコードを提供するために呼び出し元を有効にします。
『コンテキスト』構造で必要とされるデータをパッケージングする代わりに、ブロックはホストメソッドまたは関数が行うように同じレキシカルスコープからデータをキャプチャします。
ブロックコードは別々のメソッドまたは関数で実装する必要が無いので、貴方の実装コードは単純で容易に理解できるようにすることができます。

Objective-Cフレームワークにはブロックパラメータを持つ多くのメソッドがあります。
例えば、FoundationフレームワークのNSNotificationCenterクラスは、ブロック引数を持つ以下のメソッドを宣言します。

- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block

このメソッドは通知センターにオブザーバを追加します(通知は『デザインパターンを使ったアプリの合理化』で説明されています)。
指定された名前の通知がポストされると、ブロックが通知を処理するために呼び出されます。

    opQ = [[NSOperationQueue alloc] init];
    [[NSNotificationCenter defaultCenter] addObserverForName:@"CustomOperationCompleted"
            object:nil queue:opQ
        usingBlock:^(NSNotification *notif) {
        // handle the notification
    }];



●プロトコルとカテゴリ

プロトコルは、それらのクラスがプロトコルを実装している共通のスーパークラスを持っていなくても、任意のクラスで実装することができるメソッドを宣言します。
プロトコルメソッドは、任意の特定のクラスに依存しない動作を定義します。
プロトコルは単に、他のクラスが実装を担当しているインターフェイスを定義します。
貴方のクラスがプロトコルのメソッドを実装した場合、貴方のクラスはプロトコルに準拠していると言われます。

実際の観点からすると、プロトコルは任意の特定のクラスのインスタンスであることを必要とせずに、オブジェクト間の請負を確立するメソッドのリストを定義します。
この請負は、それらのオブジェクト間の通信を有効にします。
一つの目的は、発生しているイベントについて別のオブジェクトに伝える、またはそれらのイベントについての通知を必要とする場合です。

UIApplicationクラスは、アプリケーションに必要な動作を実装します。
貴方がUIApplicationのサブクラスに、アプリケーションの現在の状態についての簡単な通知を受信するよう強制する代わりに、UIApplicationクラスは割り当てられたデリゲートオブジェクトの特定のメソッドを呼び出すことによって、それらの通知を配信します。
UIApplicationDelegateプロトコルのメソッドを実装したオブジェクトは、それらの通知を受信し、適切な応答を提供することができます。

貴方のクラスのインターフェイス・ブロックをプロトコルに準拠させる、またはプロトコルを採用するには、継承しているクラスの名前の後に山括弧(< ... >)内にプロトコルの名前を置くことによって指定することができます。
次のコード行は、『初めてのiOSアプリケーション』でのUITextFieldDelegateプロトコルの採用を示します。

@interface HelloWorldViewController : UIViewController <UITextFieldDelegate> {

貴方が実装するプロトコルメソッドを宣言する必要はありません。

プロトコルの宣言は、プロトコルが親クラスを持たず、インスタンス変数を定義しない(プロパティを宣言することはできます)ということを除けば、クラスのインターフェイスのそれと似ています。
以下の例では、1つのメソッドを持つ簡単なプロトコルの宣言を示します。

@protocol MyProtocol
- (void)myProtocolMethod;
@end

多くのデリゲートプロトコルでは、プロトコルを採用することは単にプロトコルによって定義されたメソッドを実装するためです。
いくつかのプロトコルでは、プロトコルをサポートしていることを明示的に指定する必要があり、必須およびオプションのメソッドの両方を指定することができます。

Objective-Cフレームワークのヘッダファイルを調べ始めると、すぐに以下のような行に遭遇する場合があります。

@interface NSDate (NSDateCreation)

この行は括弧でカテゴリの名前を囲む構文規則によって、カテゴリを宣言しています。
カテゴリは、サブクラス化せずにクラスのインターフェイスを拡張することができる、Objective-C言語の機能です。
カテゴリ内のメソッドは(貴方のプログラムのスコープ内で)クラス型の一部となり、クラスのサブクラスの全てに継承されます。
カテゴリで定義されたメソッドを呼び出すためのクラス(またはそのサブクラス)の任意のインスタンスへ、メッセージを送信することができます。

ヘッダファイル内の関連するメソッド宣言をグループ化するための手段として、カテゴリを使用することができます。
また別のヘッダファイル内に異なるカテゴリの宣言を置くこともできます。
フレームワークでは、明瞭化のためにヘッダファイル全体でこれらの技術を使用しています。

また実装ファイル(.m)で、プライベートプロパティやプライベートメソッドを宣言するためのクラス拡張として知られている、匿名カテゴリを使用することができます。
クラス拡張は、括弧内にテキストが無いことを除けばカテゴリのように見えます。
一般的なクラス拡張は以下のようになります。

@interface MyAppDelegate ()
@property (strong) MyDataObject *data;
@end



●定義済み型とコーディング計画

Objective-Cには、特別な目的のために予約されているため、変数名として使用できないいくつかの用語があります。
これらの用語のいくつかは、@interfaceや@endなどのアットマーク(@)を接頭辞とするコンパイラディレクティブです。
その他の予約語は、定義済み型とそれらの型を伴うリテラルです。
Objective-Cは、ANSI Cでは見ることの無いリテラルと定義済み型の数を使用します。
いくつかのケースでは、これらの型とリテラルがANSI Cの対応物として置換されます。
下表に各型で許容されているリテラルを含む重要な物のいくつかを説明します。

説明とリテラル
id動的オブジェクトの型。動的および静的共に、型付け済みオブジェクトの否定リテラルはnilです。
Class動的クラス型。否定リテラルはNilです。
SELセレクタのデータ型(typedef)で、このデータ型は実行時にメソッドのシグネチャを表します。
否定リテラルはNULLです。
BOOLブール型。リテラル値はYESとNOです。

多くの場合、エラーチェックや制御フローコードで、これらの定義済み型とリテラルを使用しています。
プログラムの制御フロー文で、どのように進行させるかを決定するために、適切なリテラルをテストすることができます。
以下に例を示します。

NSDate *dateOfHire = [employee dateOfHire];
if (dateOfHire != nil) {
    // handle this case
}

このコードは、雇用の日付を表すオブジェクトがnilでない(言い換えると、有効なオブジェクトである)場合に特定の処理を行う論理です。
同じ分岐を行う簡単な方法は以下の通りです。

NSDate *dateOfHire = [employee dateOfHire];
if (dateOfHire) {
    // handle this case
}

(dateOfHireオブジェクトへの参照を必要としないと仮定すると)更にコード行を減らすことができます。

if ([employee dateOfHire]) {
    // handle this case
}

ブール値もほぼ同じ方法で扱えます。
以下の例では、isEqual:メソッドはブール値を返します。

BOOL equal = [objectA isEqual:objectB];
if (equal == YES) {
    // handle this case
}

これはオブジェクトが存在しない、あるいはnilであるかをテストできるコードで、このコードも同じ方法で短縮することができます。

Objective-Cでは、悪影響を与えることなくnilにメッセージを送信することができます。
実際には全く影響が無い
メソッドがオブジェクトを返すことになっている場合に実行時にnilを返すことを除けば、実際に全く効果はありません。
nilに送信されたメッセージからの戻り値は、何かを返すオブジェクトとして型付けされている限り、動作することが保証されています。

Objective-Cでは他にも重要な2つの予約語としてselfとsuperがあります。
最初の予約語selfは、現在のオブジェクトを参照するために、メッセージの実装内で使用することができるローカル変数で、C++のそれと同等です。
メッセージ式のレシーバとしてのみ、予約語superをselfの代わりにすることができます。
selfにメッセージを送信する場合、ランタイムは最初に現在のオブジェクトのクラスに実装しているメソッドを検索し、メソッドが見つけられなかった場合はそのスーパークラス(など)を検索します。
superにメッセージを送信した場合、ランタイムは最初にスーパークラスに実装しているメソッドを検索します。

selfとsuper両方の主な用途はメッセージを送信することです。
呼び出すメソッドがselfのクラスによって実装された場合、以下のようにselfにメッセージを送信します。

[self doSomeWork];

selfも宣言済みプロパティによって合成されたアクセサメソッドを呼び出すために、以下のようにドット表記を使用します。

NSString *theName = self.name;

多くの場合、スーパークラスから継承されたメソッドのオーバーライド(つまり再実装)で、superへメッセージを送信します。
この場合、呼び出されたメソッドはオーバーライドされたメソッドと同じシグネチャを持ちます。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Write Objective-C Code

0 CommentsPosted in 資料





QuietControl 30 wireless headphones
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
04 | 2017/05 | 06
Sun Mon Tue Wed Thu Fri Sat
- 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 31 - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

QuietControl 30 wireless headphones
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR