Objective-c-quick-guide
Objective-Cの概要
Objective-Cは、Small Talkプログラミング言語の機能を追加してオブジェクト指向言語にすることにより、Cプログラミング言語の上に開発された汎用言語です。 主にiOSおよびMac OS Xオペレーティングシステムとそのアプリケーションの開発に使用されます。
当初、Objective-CはNeXTがNeXTSTEP OS用に開発し、AppleがiOSおよびMac OS X用に引き継ぎました。
オブジェクト指向プログラミング
Objective-Cは、オブジェクト指向開発の4つの柱を含むオブジェクト指向プログラミングを完全にサポートしています-
- カプセル化
- データ隠蔽
- 継承 *多型
コード例
#import <Foundation/Foundation.h>
int main (int argc, const char* argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog (@"hello world");
[pool drain];
return 0;
}
基盤フレームワーク
Foundation Frameworkは多数の機能セットを提供し、それらを以下にリストします。
- NSArray、NSDictionary、NSSetなどの拡張データ型のリストが含まれています。
- ファイル、文字列などを操作する豊富な機能セットで構成されています。
- URL処理、日付書式設定などのユーティリティ、データ処理、エラー処理などの機能を提供します。
Objective-Cの学習
Objective-Cを学習する際に行うべき最も重要なことは、概念に集中し、言語の技術的な詳細に迷子にならないことです。
プログラミング言語を学習する目的は、優れたプログラマーになることです。つまり、新しいシステムの設計と実装、および古いシステムの保守をより効果的にすることです。
Objective-Cの使用
前述のように、Objective-CはiOSおよびMac OS Xで使用されます。 iOSベースのユーザーが多く、Mac OS Xユーザーが大幅に増加しています。 Appleは品質を第一に考えており、Objective-Cの学習を始めた人にとっては素晴らしいことです。
Objective-C環境のセットアップ
ローカル環境のセットアップ
Objective-Cプログラミング言語用に独自の環境をセットアップする場合は、コンピューターに Text Editor および The GCC Compiler をインストールする必要があります。
テキストエディタ
これは、プログラムの入力に使用されます。 いくつかのエディターの例には、Windows Notepad、OS Editコマンド、Brief、Epsilon、EMACS、vimまたはviが含まれます。
テキストエディタの名前とバージョンは、オペレーティングシステムによって異なる場合があります。 たとえば、メモ帳はWindowsで使用され、vimまたはviはLinuxまたはUNIXだけでなくWindowsでも使用できます。
エディターで作成するファイルはソースファイルと呼ばれ、プログラムのソースコードが含まれています。 Objective-Cプログラムのソースファイルには、通常、拡張子「 .m 」が付いています。
プログラミングを開始する前に、1つのテキストエディターを用意し、コンピュータープログラムを作成し、ファイルに保存し、コンパイルして、最後に実行する十分な経験があることを確認してください。
GCCコンパイラー
ソースファイルに記述されたソースコードは、プログラムの人間が読めるソースです。 CPUが実際に指定された命令に従ってプログラムを実行できるように、機械語に変換するには「コンパイル」する必要があります。
このGCCコンパイラは、ソースコードを最終的な実行可能プログラムにコンパイルするために使用されます。 プログラミング言語コンパイラに関する基本的な知識があることを前提としています。
GCCコンパイラはさまざまなプラットフォームで無料で利用できます。さまざまなプラットフォームでセットアップする手順を以下に説明します。
UNIX/Linuxでのインストール
最初の手順は、gccとObjective-Cパッケージをインストールすることです。 これはによって行われます-
$ su -
$ yum install gcc
$ yum install gcc-objc
次のステップは、次のコマンドを使用してパッケージの依存関係を設定することです-
$ yum install make libpng libpng-devel libtiff libtiff-devel libobjc
libxml2 libxml2-devel libX11-devel libXt-devel libjpeg libjpeg-devel
Objective-Cのすべての機能を入手するには、GNUStepをダウンロードしてインストールします。 これは、http://wwwmain.gnustep.org/resources/downloads.php?site = ftp%3A%2F%2Fftp.gnustep.org%2Fpub%2Fgnustep%2F#core/[http://main.gnustep.org/resources/downloads.php]。
今、私たちはダウンロードしたフォルダに切り替えて、ファイルを解凍する必要があります-
$ tar xvfz gnustep-startup-.tar.gz
今、私たちはを使用して作成されるフォルダgnustep-startupに切り替える必要があります-
$ cd gnustep-startup-<version>
次に、ビルドプロセスを設定する必要があります-
$ ./configure
その後、次のように構築できます-
$ make
私たちは最終的に環境を設定する必要があります-
$ ./usr/GNUstep/System/Library/Makefiles/GNUstep.sh
次のようにhelloWorld.m Objective-Cがあります-
#import <Foundation/Foundation.h>
int main (int argc, const char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSLog (@"hello world");
[pool drain];
return 0;
}
今、私たちはcdを使用してファイルを含むフォルダに切り替えてから次の手順を使用して、helloWorld.mと言うObjective-Cファイルをコンパイルして実行することができます-
$ gcc `gnustep-config --objc-flags`
-L/usr/GNUstep/Local/Library/Libraries
-lgnustep-base helloWorld.m -o helloWorld
$ ./helloWorld
私たちは次の出力を見ることができます-
2013-09-07 10:48:39.772 finddevguides[12906] hello world
Mac OSへのインストール
Mac OS Xを使用している場合、GCCを入手する最も簡単な方法は、AppleのWebサイトからXcode開発環境をダウンロードし、簡単なインストール手順に従うことです。 Xcodeをセットアップすると、C/C ++用のGNUコンパイラを使用できるようになります。
Xcodeは現在、https://developer.apple.com/technologies/tools/[developer.apple.com/technologies/tools/]で入手できます。
Windowsへのインストール
WindowsでObjective-Cプログラムを実行するには、MinGWとGNUStep Coreをインストールする必要があります。 どちらもhttps://www.gnu.org/software/gnustep/windows/installerlから入手できます。
最初に、MSYS/MinGW Systemパッケージをインストールする必要があります。 次に、GNUstep Coreパッケージをインストールする必要があります。 どちらもWindowsインストーラーを提供しますが、これは一目瞭然です。
次に、[スタート]→ [すべてのプログラム]→ [GNUstep]→ [シェル]を選択して、Objective-CとGNUstepを使用します。
helloWorld.mを含むフォルダーに切り替えます
を使用してプログラムをコンパイルできます-
$ gcc `gnustep-config --objc-flags`
-L/GNUstep/System/Library/Libraries hello.m -o hello -lgnustep-base -lobjc
を使用してプログラムを実行できます-
./hello.exe
私たちは次の出力を取得します-
2013-09-07 10:48:39.772 finddevguides[1200] hello world
Objective-Cプログラムの構造
Objective-Cプログラミング言語の基本的な構成要素を検討する前に、今後の章で参照として使用できるように、最低限のObjective-Cプログラム構造を見てみましょう。
Objective-C Hello Worldの例
Objective-Cプログラムは、基本的に次の部分で構成されています-
- プリプロセッサコマンド
- インタフェース
- 実装
- 方法
- 変数
- ステートメントと式
- コメント
「Hello World」という言葉を出力する簡単なコードを見てみましょう-
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
@end
int main() {
/*my first program in Objective-C*/
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
return 0;
}
上記のプログラムのさまざまな部分を見てみましょう-
- プログラムの最初の行_#import <Foundation/Foundation.h> _はプリプロセッサコマンドで、Objective-Cコンパイラに実際のコンパイルの前にFoundation.hファイルを含めるように指示します。
- 次の行_ @ interface SampleClass:NSObject_は、インターフェースの作成方法を示しています。 すべてのオブジェクトの基本クラスであるNSObjectを継承します。
- 次の行_-(void)sampleMethod; _は、メソッドの宣言方法を示しています。
- 次の行_ @ end_は、インターフェースの終わりを示します。
- 次の行_ @ implementation SampleClass_は、インターフェイスSampleClassを実装する方法を示しています。
- 次の行_-(void)sampleMethod \ {} _は、sampleMethodの実装を示しています。
- 次の行_ @ end_は、実装の終了を示します。
- 次の行_int main()_は、プログラムの実行が開始されるメイン関数です。
- 次の行/…/はコンパイラによって無視され、プログラムにコメントを追加するために追加されました。 そのため、このような行はプログラムではコメントと呼ばれます。
- 次の行_NSLog(…)_は、Objective-Cで使用可能な別の関数であり、「Hello、World!」というメッセージが表示されます。画面に表示されます。
- 次の行 return 0; はmain()functionを終了し、値0を返します。
Objective-Cプログラムのコンパイルと実行
プログラムをコンパイルして実行すると、次の結果が得られます。
2017-10-06 07:48:32.020 demo[65832] Hello, World!
Objective-Cの基本構文
Objective-Cプログラムの基本構造を見てきましたので、Objective-Cプログラミング言語の他の基本的な構成要素を簡単に理解できます。
Objective-Cのトークン
Objective-Cプログラムはさまざまなトークンで構成され、トークンはキーワード、識別子、定数、文字列リテラル、またはシンボルのいずれかです。 たとえば、次のObjective-Cステートメントは6つのトークンで構成されています-
NSLog(@"Hello, World! \n");
個々のトークンは-
NSLog
@
(
"Hello, World! \n"
)
;
セミコロン;
Objective-Cプログラムでは、セミコロンはステートメントターミネータです。 つまり、個々のステートメントはセミコロンで終了する必要があります。 1つの論理エンティティの終わりを示します。
たとえば、以下は2つの異なるステートメントです-
NSLog(@"Hello, World! \n");
return 0;
コメント
コメントは、Objective-Cプログラムのヘルプテキストに似ており、コンパイラによって無視されます。 以下に示すように、/で始まり、文字/で終了します-
/*my first program in Objective-C*/
コメントにコメントを含めることはできません。また、文字列または文字リテラル内にコメントを含めることはできません。
識別子
Objective-C識別子は、変数、関数、またはその他のユーザー定義アイテムを識別するために使用される名前です。 識別子は、文字A〜Zまたはa〜zまたはアンダースコア_で始まり、その後に0個以上の文字、アンダースコア、および数字(0〜9)が続きます。
Objective-Cでは、識別子内で@、$、%などの句読点を使用できません。 Objective-Cは、*大文字と小文字を区別する*プログラミング言語です。 したがって、_Manpower_と_manpower_は、Objective-Cの2つの異なる識別子です。 ここに受け入れ可能な識別子のいくつかの例があります-
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
キーワード
次のリストは、Objective-Cの予約語のいくつかを示しています。 これらの予約語は、定数、変数、またはその他の識別子名として使用できません。
| auto | else | long | switch |
| break | enum | register | typedef |
| case | extern | return | union |
| char | float | short | unsigned |
| const | for | signed | void |
| continue | goto | sizeof | volatile |
| default | if | static | while |
| do | int | struct | _Packed |
| double | protocol | interface | implementation |
| NSObject | NSInteger | NSNumber | CGFloat |
| property | nonatomic; | retain | strong |
| weak | unsafe_unretained; | readwrite | readonly |
Objective-Cの空白
コメントが含まれている可能性のある空白のみを含む行は、空白行と呼ばれ、Objective-Cコンパイラでは完全に無視されます。
空白とは、Objective-Cで空白、タブ、改行文字、コメントを記述するために使用される用語です。 空白は、ステートメントの一部を別の部分から分離し、コンパイラーがステートメント内の1つの要素(intなど)がどこで終わり、次の要素が始まるかをコンパイラーが識別できるようにします。 したがって、次のステートメントで-
int age;
コンパイラーが区別できるようにするには、intとageの間に少なくとも1つの空白文字(通常はスペース)が必要です。 一方、次のステートメントでは、
fruit = apples + oranges; //get the total fruit
果物と=、または=とリンゴの間には空白文字は必要ありませんが、読みやすくするために空白文字を自由に含めることができます。
Objective-Cのデータ型
Objective-Cプログラミング言語では、データ型は、異なる型の変数または関数を宣言するために使用される広範なシステムを指します。 変数のタイプによって、ストレージ内で占めるスペースの量と、格納されているビットパターンの解釈方法が決まります。
Objective-Cのタイプは、次のように分類できます-
| Sr.No. | Types & Description |
|---|---|
| 1 |
Basic Types − これらは算術型であり、2つの型で構成されます:(a)整数型と(b)浮動小数点型。 |
| 2 |
Enumerated types − これらも算術型であり、プログラム全体で特定の離散整数値のみを割り当てることができる変数を定義するために使用されます。 |
| 3 |
The type void − 型指定子_void_は、使用可能な値がないことを示します。 |
| 4 |
Derived types − それらには、(a)ポインター型、(b)配列型、(c)構造体型、(d)ユニオン型、および(e)関数型が含まれます。 |
配列型と構造体型は、集合型と総称されます。 関数のタイプは、関数の戻り値のタイプを指定します。 次のセクションで基本的なタイプについて説明しますが、他のタイプについては今後の章で説明します。
整数型
次の表は、標準の整数型とそのストレージサイズと値の範囲の詳細を示しています-
| Type | Storage size | Value range |
|---|---|---|
| char | 1 byte | -128 to 127 or 0 to 255 |
| unsigned char | 1 byte | 0 to 255 |
| signed char | 1 byte | -128 to 127 |
| int | 2 or 4 bytes | -32,768 to 32,767 or -2,147,483,648 to 2,147,483,647 |
| unsigned int | 2 or 4 bytes | 0 to 65,535 or 0 to 4,294,967,295 |
| short | 2 bytes | -32,768 to 32,767 |
| unsigned short | 2 bytes | 0 to 65,535 |
| long | 4 bytes | -2,147,483,648 to 2,147,483,647 |
| unsigned long | 4 bytes | 0 to 4,294,967,295 |
特定のプラットフォームで型または変数の正確なサイズを取得するには、 sizeof 演算子を使用できます。 式_sizeof(type)_は、オブジェクトまたはタイプのストレージサイズをバイト単位で生成します。 以下は、任意のマシンでint型のサイズを取得する例です-
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Storage size for int : %d \n", sizeof(int));
return 0;
}
上記のプログラムをコンパイルして実行すると、Linuxで次の結果が生成されます-
2013-09-07 22:21:39.155 demo[1340] Storage size for int : 4
浮動小数点型
次の表は、ストレージサイズと値の範囲、およびその精度を備えた標準の浮動小数点型の詳細を示しています-
| Type | Storage size | Value range | Precision |
|---|---|---|---|
| float | 4 byte | 1.2E-38 to 3.4E+38 | 6 decimal places |
| double | 8 byte | 2.3E-308 to 1.7E+308 | 15 decimal places |
| long double | 10 byte | 3.4E-4932 to 1.1E+4932 | 19 decimal places |
ヘッダーファイルfloat.hは、これらの値およびプログラムで実数のバイナリ表現に関するその他の詳細を使用できるマクロを定義します。 次の例は、フロート型とその範囲値によって取得されたストレージスペースを印刷します-
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Storage size for float : %d \n", sizeof(float));
return 0;
}
上記のプログラムをコンパイルして実行すると、Linuxで次の結果が生成されます-
2013-09-07 22:22:21.729 demo[3927] Storage size for float : 4
ボイドタイプ
voidタイプは、使用可能な値がないことを指定します。 それは3種類の状況で使用されます-
| Sr.No. | Types and Description |
|---|---|
| 1 |
Function returns as void Objective-Cには、値を返さないさまざまな関数があります。これらの関数はvoidを返します。 戻り値のない関数の戻り値の型はvoidです。 たとえば、 void exit(int status); |
| 2 |
Function arguments as void Objective-Cには、パラメーターを受け入れないさまざまな関数があります。 パラメーターを持たない関数は、voidとして受け入れることができます。 たとえば、 int rand(void); |
現時点ではvoidタイプは理解できない可能性があるため、先に進みましょう。これらの概念については、今後の章で説明します。
Objective-Cの変数
変数は、プログラムが操作できるストレージ領域に付けられた名前に他なりません。 Objective-Cの各変数には特定のタイプがあり、変数のメモリのサイズとレイアウトを決定します。そのメモリ内に保存できる値の範囲。変数に適用できる一連の操作。
変数の名前は、文字、数字、およびアンダースコア文字で構成できます。 文字またはアンダースコアで始まる必要があります。 Objective-Cでは大文字と小文字が区別されるため、大文字と小文字は区別されます。 前の章で説明した基本タイプに基づいて、次の基本変数タイプがあります-
| Sr.No. | Type & Description |
|---|---|
| 1 |
char 通常、単一のオクテット(1バイト)。 これは整数型です。 |
| 2 |
int マシンの整数の最も自然なサイズ。 |
| 3 |
float 単精度浮動小数点値。 |
| 4 |
double 倍精度の浮動小数点値。 |
| 5 |
void タイプがないことを表します。 |
Objective-Cプログラミング言語では、その他のさまざまなタイプの変数を定義することもできます。これについては、列挙、ポインター、配列、構造、ユニオンなどの後続の章で説明します。 この章では、基本的な変数タイプのみを学習します。
Objective-Cの変数定義
変数の定義とは、変数のストレージを作成する場所と量をコンパイラーに伝えることです。 変数の定義は、データ型を指定し、次のようにその型の1つ以上の変数のリストが含まれています-
type variable_list;
ここで、 type はchar、w_char、int、float、double、boolまたは任意のユーザー定義オブジェクトなどを含む有効なObjective-Cデータ型である必要があり、 variable_list は1つ以上の識別子名で構成されます。コンマ。 いくつかの有効な宣言がここに示されています-
int i, j, k;
char c, ch;
float f, salary;
double d;
行 int i、j、k; は、変数i、jおよびkを宣言および定義します。これは、int型のi、j、kという名前の変数を作成するようコンパイラーに指示します。
変数は、宣言で初期化(初期値を割り当て)できます。 初期化子は、等号とそれに続く定数式で構成されます-
type variable_name = value;
いくつかの例は-
extern int d = 3, f = 5; //declaration of d and f.
int d = 3, f = 5; //definition and initializing d and f.
byte z = 22; //definition and initializes z.
char x = 'x'; //the variable x has the value 'x'.
初期化子なしの定義の場合:静的ストレージ期間を持つ変数は、暗黙的にNULLで初期化されます(すべてのバイトの値は0です)他のすべての変数の初期値は未定義です。
Objective-Cの変数宣言
変数宣言は、指定された型と名前を持つ変数が1つ存在することをコンパイラに保証するため、コンパイラは、変数に関する完全な詳細を必要とせずに、さらにコンパイルを進めることができます。 変数宣言はコンパイル時にのみ意味を持ち、コンパイラはプログラムのリンク時に実際の変数宣言を必要とします。
変数宣言は、複数のファイルを使用していて、プログラムのリンク時に使用できるファイルの1つで変数を定義する場合に役立ちます。 extern キーワードを使用して、任意の場所で変数を宣言します。 ただし、Objective-Cプログラムでは変数を複数回宣言できますが、ファイル、関数、またはコードブロックで一度だけ定義できます。
例
次の例を試してください。変数は上部で宣言されていますが、メイン関数内で定義および初期化されています-
#import <Foundation/Foundation.h>
//Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main () {
/*variable definition:*/
int a, b;
int c;
float f;
/*actual initialization*/
a = 10;
b = 20;
c = a + b;
NSLog(@"value of c : %d \n", c);
f = 70.0/3.0;
NSLog(@"value of f : %f \n", f);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-07 22:43:31.695 demo[14019] value of c : 30
2013-09-07 22:43:31.695 demo[14019] value of f : 23.333334
同じ概念が関数宣言にも適用され、宣言時に関数名を指定し、実際の定義は他のどこでも指定できます。 次の例では、C関数を使用して説明し、ご存じのとおりObjective-CはCスタイル関数もサポートしています-
//function declaration
int func();
int main() {
//function call
int i = func();
}
//function definition
int func() {
return 0;
}
Objective-Cの左辺値と右辺値
Objective-Cには2種類の式があります-
- lvalue -メモリ位置を参照する式は「lvalue」式と呼ばれます。 左辺値は、割り当ての左辺または右辺として表示される場合があります。
- rvalue -rvalueという用語は、メモリ内のあるアドレスに格納されているデータ値を指します。 右辺値は、値を割り当てることができない式です。つまり、右辺に割り当てることができますが、割り当ての左側ではありません。
変数は左辺値であるため、割り当ての左側に表示される場合があります。 数値リテラルは右辺値であるため、割り当てられない可能性があり、左側に表示できません。 以下は有効なステートメントです-
int g = 20;
しかし、以下は有効なステートメントではなく、コンパイル時エラーを生成します-
10 = 20;
Objective-Cの定数
定数は、プログラムの実行中に変更されない可能性がある固定値を参照します。 これらの固定値は*リテラル*とも呼ばれます。
定数は、_整数定数、浮動定数、文字定数、または文字列リテラル_などの基本データ型のいずれかです。 列挙定数もあります。
*constants* は通常の変数と同様に扱われますが、定義後に値を変更することはできません。
整数リテラル
整数リテラルは、10進、8進、または16進定数です。 プレフィックスは、基数または基数を指定します。16進数の場合は0xまたは0X、8進数の場合は0、10進数の場合は何もありません。
整数リテラルには、UとLを組み合わせたサフィックスを付けることもできます。それぞれ、符号なしとロングを表します。 接尾辞は大文字でも小文字でも、任意の順序で指定できます。
ここに整数リテラルのいくつかの例があります-
212 /*Legal*/
215u /*Legal*/
0xFeeL /*Legal*/
078 /*Illegal: 8 is not an octal digit*/
032UU /*Illegal: cannot repeat a suffix*/
以下は、整数リテラルのさまざまなタイプの他の例です-
85 /*decimal*/
0213 /*octal*/
0x4b /*hexadecimal*/
30 /*int*/
30u /*unsigned int*/
30l /*long*/
30ul /*unsigned long*/
浮動小数点リテラル
浮動小数点リテラルには、整数部、小数点、小数部、指数部があります。 浮動小数点リテラルは、10進数形式または指数形式で表現できます。
小数点形式を使用して表す場合は、小数点、指数、またはその両方を含める必要があり、指数形式を使用して表す場合は、整数部、小数部、またはその両方を含める必要があります。 符号付き指数は、eまたはEによって導入されます。
浮動小数点リテラルの例をいくつか示します-
3.14159 /*Legal*/
314159E-5L /*Legal*/
510E /*Illegal: incomplete exponent*/
210f /*Illegal: no decimal or exponent*/
.e55 /*Illegal: missing integer or fraction*/
文字定数
文字リテラルは、一重引用符で囲まれます(例: 'x')。 char 型の単純な変数に格納できます。
文字リテラルは、プレーン文字(例: 'x')、エスケープシーケンス(例: '\ t')、またはユニバーサル文字(例: '\ u02C0')です。
Cにはバックスラッシュが続く特定の文字があり、特別な意味を持ち、改行(\ n)またはタブ(\ t)のような表現に使用されます。 ここでは、そのようなエスケープシーケンスコードのいくつかのリストを持っています-
| Escape sequence | Meaning |
|---|---|
| \\ | \ character |
| \' | ' character |
| \" | " character |
| \? | ? character |
| \a | Alert or bell |
| \b | Backspace |
| \f | Form feed |
| \n | Newline |
| \r | Carriage return |
| \t | Horizontal tab |
| \v | Vertical tab |
| \ooo | Octal number of one to three digits |
| \xhh . . . | Hexadecimal number of one or more digits |
以下は、いくつかのエスケープシーケンス文字を表示する例です-
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello\tWorld\n\n");
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-07 22:17:17.923 demo[17871] Hello World
文字列リテラル
文字列リテラルまたは定数は、二重引用符 ""で囲まれています。 文字列には、文字リテラルに類似した文字が含まれます:プレーン文字、エスケープシーケンス、およびユニバーサル文字。 文字列リテラルを使用して長い行を複数の行に分割し、それらを空白で区切ります。
文字列リテラルの例を次に示します。 3つの形式はすべて同じ文字列です。
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
定数の定義
Cには定数を定義する2つの簡単な方法があります-
- *#define *プリプロセッサを使用します。
- const キーワードを使用します。
#defineプリプロセッサ
以下は、#defineプリプロセッサを使用して定数を定義する形式です-
#define identifier value
次の例では、詳細に説明します-
#import <Foundation/Foundation.h>
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main() {
int area;
area = LENGTH * WIDTH;
NSLog(@"value of area : %d", area);
NSLog(@"%c", NEWLINE);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-07 22:18:16.637 demo[21460] value of area : 50
2013-09-07 22:18:16.638 demo[21460]
constキーワード
次のように、 const プレフィックスを使用して、特定のタイプの定数を宣言できます-
const type variable = value;
次の例では、詳細に説明します-
#import <Foundation/Foundation.h>
int main() {
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
NSLog(@"value of area : %d", area);
NSLog(@"%c", NEWLINE);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-07 22:19:24.780 demo[25621] value of area : 50
2013-09-07 22:19:24.781 demo[25621]
CAPITALSで定数を定義することは、優れたプログラミング手法であることに注意してください。
Objective-Cオペレーター
演算子は、特定の数学的または論理的な操作を実行するようコンパイラーに指示する記号です。 Objective-C言語は組み込みの演算子が豊富であり、次の種類の演算子を提供します-
- 算術演算子
- 関係演算子
- 論理演算子
- ビット演算子
- 割り当て演算子
- その他の演算子
このチュートリアルでは、算術演算、リレーショナル演算、論理演算、ビット単位の代入、およびその他の演算子を1つずつ説明します。
算術演算子
次の表は、Objective-C言語でサポートされているすべての算術演算子を示しています。 変数 A が10を保持し、変数 B が20を保持すると仮定します-
リンク:/objective_c/objective_c_arithmetic_operators [例を表示]
| Operator | Description | Example |
|---|---|---|
| + | Adds two operands | A + B will give 30 |
| - | Subtracts second operand from the first | A - B will give -10 |
| * | Multiplies both operands | A* B will give 200 |
| / | Divides numerator by denominator | B/A will give 2 |
| % | Modulus Operator and remainder of after an integer division | B % A will give 0 |
| ++ | Increment operator increases integer value by one | A++ will give 11 |
| — | Decrement operator decreases integer value by one | A-- will give 9 |
関係演算子
次の表は、Objective-C言語でサポートされているすべての関係演算子を示しています。 変数 A が10を保持し、変数 B が20を保持すると仮定します-
リンク:/objective_c/objective_c_relational_operators [例を表示]
| Operator | Description | Example |
|---|---|---|
| == | Checks if the values of two operands are equal or not; if yes, then condition becomes true. | (A == B) is not true. |
| != | Checks if the values of two operands are equal or not; if values are not equal, then condition becomes true. | (A != B) is true. |
| > | Checks if the value of left operand is greater than the value of right operand; if yes, then condition becomes true. | (A > B) is not true. |
| < | Checks if the value of left operand is less than the value of right operand; if yes, then condition becomes true. | (A < B) is true. |
| >= | Checks if the value of left operand is greater than or equal to the value of right operand; if yes, then condition becomes true. | (A >= B) is not true. |
| ⇐ | Checks if the value of left operand is less than or equal to the value of right operand; if yes, then condition becomes true. | (A ⇐ B) is true. |
論理演算子
次の表は、Objective-C言語でサポートされているすべての論理演算子を示しています。 変数 A が1を保持し、変数 B が0を保持すると仮定します-
リンク:/objective_c/objective_c_logical_operators [例を表示]
| Operator | Description | Example |
|---|---|---|
| && | Called Logical AND operator. If both the operands are non zero then condition becomes true. | (A && B) is false. |
| Called Logical OR Operator. If any of the two operands is non zero then condition becomes true. | (A | |
| B) is true. | ! | Called Logical NOT Operator. Use to reverses the logical state of its operand. If a condition is true, then Logical NOT operator will make false. |
ビット演算子
ビットごとの演算子はビットに対して機能し、ビットごとの演算を実行します。 &、|、および^の真理値表は次のとおりです-
| p | q | p & q | p | q |
|---|---|---|---|---|
| p ^ q | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 |
| 0 | 1 | 0 | 0 | 1 |
A = 60であると仮定します。およびB = 13;今バイナリ形式では、次のようになります-
A = 0011 1100
B = 0000 1101
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
〜A = 1100 0011
Objective-C言語でサポートされているビット単位の演算子を次の表にリストします。 変数Aが60を保持し、変数Bが13を保持すると仮定します-
リンク:/objective_c/objective_c_bitwise_operators [例を表示]
[cols=",,",options="header",]
|===
|Operator |Description |Example |& |Binary AND Operator copies a bit to the result if it exists in both operands. |(A & B) will give 12, which is 0000 1100 || |Binary OR Operator copies a bit if it exists in either operand. |(A | B) will give 61, which is 0011 1101 |^ |Binary XOR Operator copies the bit if it is set in one operand but not both. |(A ^ B) will give 49, which is 0011 0001 |~ |Binary Ones Complement Operator is unary and has the effect of 'flipping' bits. |(~A ) will give -61, which is 1100 0011 in 2's complement form. |<< |Binary Left Shift Operator. The left operands value is moved left by the number of bits specified by the right operand. |A << 2 will give 240, which is 1111 0000 |>> |Binary Right Shift Operator. The left operands value is moved right by the number of bits specified by the right operand. |A >> 2 will give 15, which is 0000 1111
|===
=== 割り当て演算子
Objective-C言語でサポートされている次の代入演算子があります-
リンク:/objective_c/objective_c_assignment_operators [例を表示]
[cols=",,",options="header",]
|===
|Operator |Description |Example |= |Simple assignment operator, Assigns values from right side operands to left side operand |C = A + B will assign value of A + B into C |+= |Add AND assignment operator, It adds right operand to the left operand and assigns the result to left operand |C += A is equivalent to C = C + A |-= |Subtract AND assignment operator, It subtracts right operand from the left operand and assigns the result to left operand |C -= A is equivalent to C = C - A |*= |Multiply AND assignment operator, It multiplies right operand with the left operand and assigns the result to left operand |C *= A is equivalent to C = C * A |/= |Divide AND assignment operator, It divides left operand with the right operand and assigns the result to left operand |C/= A is equivalent to C = C/A |%= |Modulus AND assignment operator, It takes modulus using two operands and assigns the result to left operand |C %= A is equivalent to C = C % A |<<= |Left shift AND assignment operator |C <<= 2 is same as C = C << 2 |>>= |Right shift AND assignment operator |C >>= 2 is same as C = C >> 2 |&= |Bitwise AND assignment operator |C &= 2 is same as C = C & 2 |^= |bitwise exclusive OR and assignment operator |C ^= 2 is same as C = C ^ 2 ||= |bitwise inclusive OR and assignment operator |C |= 2 is same as C = C | 2
|===
=== その他の演算子&map; sizeof&ternary
*sizeof* や*?など、他の重要な演算子はほとんどありません。 :* Objective-C言語でサポートされています。
リンク:/objective_c/objective_c_sizeof_operator [例を表示]
[cols=",,",options="header",]
|===
|Operator |Description |Example |sizeof() |Returns the size of an variable. |sizeof(a), where a is integer, will return 4. |& |Returns the address of an variable. |&a; will give actual address of the variable. |* |Pointer to a variable. |*a; will pointer to a variable. |? : |Conditional Expression |If Condition is true ? Then value X : Otherwise value Y
|===
=== Objective-Cでの演算子の優先順位
演算子の優先順位は、式内の用語のグループ化を決定します。 これは、式の評価方法に影響します。 特定の演算子は、他の演算子よりも優先順位が高くなっています。たとえば、乗算演算子は加算演算子よりも優先順位が高い-
たとえば、x = 7 + 3 * 2;ここでは、演算子*の優先順位が+よりも高いため、xには20ではなく13が割り当てられます。したがって、最初に3 * 2で乗算され、7に加算されます。
ここでは、優先順位が最も高い演算子が表の上部に表示され、優先順位が最も低い演算子が下部に表示されます。 式内では、優先順位の高い演算子が最初に評価されます。
[cols=",,",options="header",]
|===
|Category |Operator |Associativity |Postfix |() [] -> . ++ - - |Left to right |Unary |+ - ! ~ ++ - - (type)* & sizeof |Right to left |Multiplicative | */% |Left to right |Additive |+ - |Left to right |Shift |<< >> |Left to right |Relational |< <= > >= |Left to right |Equality |== != |Left to right |Bitwise XOR |^ |Left to right |Bitwise OR || |Left to right |Logical AND |&& |Left to right |Logical OR ||| |Left to right |Conditional |?: |Right to left |Assignment |= += -=* =/= %=>>= <<= &= ^= |= |Right to left |Comma |, |Left to right
|===
Objective-Cループ
コードのブロックを数回実行する必要がある場合があります。 一般に、ステートメントは順番に実行されます。関数の最初のステートメントが最初に実行され、次に2番目のステートメントが実行されます。 プログラミング言語は、より複雑な実行パスを可能にするさまざまな制御構造を提供します。 ループステートメントを使用すると、ステートメントまたはステートメントのグループを複数回実行できます。ほとんどのプログラミング言語では、ループステートメントの一般的な形式は次のとおりです-
Objective-Cプログラミング言語は、ループ要件を処理するために次のタイプのループを提供します。 詳細を確認するには、次のリンクをクリックしてください。
| Sr.No. | Loop Type & Description |
|---|---|
| 1 |
特定の条件が真の間、ステートメントまたはステートメントのグループを繰り返します。 ループ本体を実行する前に条件をテストします。 |
| 2 |
一連のステートメントを複数回実行し、ループ変数を管理するコードを短縮します。 |
| 3 |
whileステートメントと似ていますが、ループ本体の最後で条件をテストします。 |
| 4 |
while、for、またはdo..whileループ内で1つ以上のループを使用できます。 |
ループ制御ステートメント
ループ制御ステートメントは、通常のシーケンスから実行を変更します。 実行がスコープを離れると、そのスコープで作成されたすべての自動オブジェクトが破棄されます。
Objective-Cは、次の制御ステートメントをサポートしています。 詳細を確認するには、次のリンクをクリックしてください。
| Sr.No. | Control Statement & Description |
|---|---|
| 1 |
|
| 2 |
ループがその本体の残りをスキップし、反復する前にその状態をすぐに再テストします。 |
無限ループ
条件が決して偽にならない場合、ループは無限ループになります。 for ループは伝統的にこの目的に使用されます。 forループを形成する3つの式はいずれも必要ないため、条件式を空のままにして無限ループを作成できます。
#import <Foundation/Foundation.h>
int main () {
for( ; ; ) {
NSLog(@"This loop will run forever.\n");
}
return 0;
}
条件式が存在しない場合、trueと見なされます。 初期化式と増分式を使用できますが、Objective-Cプログラマーはより一般的にfor(;;)コンストラクトを使用して無限ループを示します。
Objective-Cの意思決定
意思決定構造では、プログラマーが、プログラムによって評価またはテストされる1つ以上の条件を、条件が真であると判断された場合に実行されるステートメント、およびオプションで条件が実行された場合に実行される他のステートメントとともに指定する必要があります偽と判断されます。
以下は、ほとんどのプログラミング言語で見られる典型的な意思決定構造の一般的な形式です-
Objective-Cプログラミング言語は、すべての*非ゼロ*および*非ヌル*値を true と見なし、ゼロ*または *null の場合、 false 値と見なされます。
Objective-Cプログラミング言語は、次のタイプの意思決定ステートメントを提供します。 詳細を確認するには、次のリンクをクリックしてください-
| Sr.No. | Statement & Description |
|---|---|
| 1 |
|
| 2 |
|
| 3 |
1つの if または else if ステートメントを別の if または else if ステートメント内で使用できます。 |
| 4 |
|
| 5 |
1つの switch ステートメントを別の switch ステートメント内で使用できます。 |
は? :オペレーター
条件演算子? :*前の章の *if … else ステートメントを置き換えるために使用できます。 それは次の一般的な形式を持っています-
Exp1 ? Exp2 : Exp3;
Exp1、Exp2、およびExp3は式です。 コロンの使用と配置に注意してください。
aの値 式は次のように決定されます:Exp1が評価されます。 真の場合、Exp2が評価され、?全体の値になります。 式です。 Exp1がfalseの場合、Exp3が評価され、その値が式の値になります。
Objective-Cの機能
関数は、一緒にタスクを実行するステートメントのグループです。 すべてのObjective-Cプログラムには、* main()*という1つのC関数があり、最も単純なプログラムはすべて、追加の関数を定義できます。
コードを別々の機能に分割できます。 コードを異なる関数に分割する方法はユーザー次第ですが、論理的には通常、各関数が特定のタスクを実行するように分割されます。
関数*宣言*は、関数の名前、戻り値の型、およびパラメーターについてコンパイラーに通知します。 関数 definition は、関数の実際の本体を提供します。
基本的にObjective-Cでは、関数をメソッドとして呼び出します。
Objective-C基盤フレームワークは、プログラムが呼び出すことができる多数の組み込みメソッドを提供します。 たとえば、文字列を別の文字列に追加するメソッド* appendString()*。
メソッドは、関数、サブルーチン、またはプロシージャなどのさまざまな名前で知られています。
メソッドの定義
Objective-Cプログラミング言語のメソッド定義の一般的な形式は次のとおりです-
- (return_type) method_name:( argumentType1 )argumentName1
joiningArgument2:( argumentType2 )argumentName2 ...
joiningArgumentn:( argumentTypen )argumentNamen {
body of the function
}
Objective-Cプログラミング言語のメソッド定義は、_method header_と_method body_で構成されています。 ここにメソッドのすべての部分があります-
- 戻りタイプ-メソッドは値を返す場合があります。 return_type は、関数が返す値のデータ型です。 一部のメソッドは、値を返さずに目的の操作を実行します。 この場合、return_typeはキーワード void です。
- メソッド名-これはメソッドの実際の名前です。 メソッド名とパラメーターリストが一緒になってメソッドシグネチャを構成します。
- 引数-引数はプレースホルダーのようなものです。 関数が呼び出されると、引数に値を渡します。 この値は、実パラメーターまたは引数と呼ばれます。 パラメータリストは、メソッドの引数のタイプ、順序、および数を参照します。 引数はオプションです。つまり、メソッドには引数が含まれない場合があります。
- Joining Argument -ジョインの引数は、呼び出し中に読みやすく、明確にするためのものです。
- メソッド本体-メソッド本体には、メソッドの動作を定義するステートメントのコレクションが含まれています。
例
以下は、* max()*というメソッドのソースコードです。 このメソッドは、num1とnum2の2つのパラメータを取り、2つの間の最大値を返します-
/*function returning the max between two numbers*/
- (int) max:(int) num1 secondNumber:(int) num2 {
/*local variable declaration*/
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}
メソッド宣言
メソッド*宣言*は、コンパイラーに関数名とメソッドの呼び出し方法を伝えます。 関数の実際の本体は個別に定義できます。
メソッド宣言には次の部分があります-
- (return_type) function_name:( argumentType1 )argumentName1
joiningArgument2:( argumentType2 )argumentName2 ...
joiningArgumentn:( argumentTypen )argumentNamen;
上記の関数max()の場合、以下はメソッド宣言です-
-(int) max:(int)num1 andNum2:(int)num2;
あるソースファイルでメソッドを定義し、別のファイルでそのメソッドを呼び出す場合、メソッド宣言が必要です。 そのような場合、関数を呼び出すファイルの先頭で関数を宣言する必要があります。
メソッドを呼び出す
Objective-Cメソッドを作成するときに、関数が何をする必要があるかを定義します。 メソッドを使用するには、その関数を呼び出して定義済みのタスクを実行する必要があります。
プログラムが関数を呼び出すと、プログラム制御は呼び出されたメソッドに転送されます。 呼び出されたメソッドは定義されたタスクを実行し、returnステートメントが実行されるか、関数終了の閉じブレースに達すると、プログラム制御をメインプログラムに戻します。
メソッドを呼び出すには、メソッド名とともに必要なパラメーターを渡すだけでよく、メソッドが値を返す場合、戻り値を保存できます。 たとえば-
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
/*method declaration*/
- (int)max:(int)num1 andNum2:(int)num2;
@end
@implementation SampleClass
/*method returning the max between two numbers*/
- (int)max:(int)num1 andNum2:(int)num2 {
/*local variable declaration*/
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}
@end
int main () {
/*local variable definition*/
int a = 100;
int b = 200;
int ret;
SampleClass *sampleClass = [[SampleClass alloc]init];
/*calling a method to get max value*/
ret = [sampleClass max:a andNum2:b];
NSLog(@"Max value is : %d\n", ret );
return 0;
}
main()関数とともにmax()関数を保持し、ソースコードをコンパイルしました。 最終的な実行可能ファイルを実行している間、それは次の結果を生成します-
2013-09-07 22:28:45.912 demo[26080] Max value is : 200
関数の引数
関数が引数を使用する場合、引数の値を受け入れる変数を宣言する必要があります。 これらの変数は、関数の*仮パラメータ*と呼ばれます。
仮パラメータは、関数内の他のローカル変数のように動作し、関数に入ると作成され、終了すると破棄されます。
関数を呼び出している間、引数を関数に渡すことができる2つの方法があります-
| Sr.No. | Call Type & Description |
|---|---|
| 1 |
このメソッドは、引数の実際の値を関数の仮パラメーターにコピーします。 この場合、関数内のパラメーターを変更しても、引数には影響しません。 |
| 2 |
このメソッドは、引数のアドレスを仮パラメーターにコピーします。 関数内では、呼び出しで使用される実際の引数にアクセスするためにアドレスが使用されます。 これは、パラメーターに加えられた変更が引数に影響することを意味します。 |
デフォルトでは、Objective-Cは*値による呼び出し*を使用して引数を渡します。 一般に、これは、関数内のコードが関数の呼び出しに使用される引数を変更できないことを意味します。max()関数の呼び出し中の上記の例は同じメソッドを使用しました。
Objective-Cブロック
Objective-Cクラスは、データと関連する動作を組み合わせるオブジェクトを定義します。 場合によっては、メソッドのコレクションではなく、単一のタスクまたは動作の単位を表すことだけが理にかなっています。
ブロックは、C、Objective-C、およびC ++に追加された言語レベルの機能であり、値のようにメソッドまたは関数に渡すことができるコードの個別のセグメントを作成できます。 ブロックはObjective-Cオブジェクトです。つまり、NSArrayやNSDictionaryなどのコレクションに追加できます。 また、外側のスコープから値をキャプチャする機能も備えており、他のプログラミング言語のクロージャーまたはラムダに似ています。
単純なブロック宣言構文
returntype (^blockName)(argumentType);
シンプルなブロック実装
returntype (^blockName)(argumentType)= ^{
};
これは簡単な例です
void (^simpleBlock)(void) = ^{
NSLog(@"This is a block");
};
を使用してブロックを呼び出すことができます
simpleBlock();
ブロックは引数を取り、値を返します
ブロックは、メソッドや関数のように引数を取り、値を返すこともできます。
以下は、引数と戻り値を使用してブロックを実装および呼び出す簡単な例です。
double (^multiplyTwoValues)(double, double) =
^(double firstValue, double secondValue) {
return firstValue * secondValue;
};
double result = multiplyTwoValues(2,4);
NSLog(@"The result is %f", result);
型定義を使用するブロック
ブロック内でtypedefを使用する簡単な例を次に示します。 現在のところ、このサンプルは*オンラインコンパイラ*では機能しません*。 XCode を使用して同じことを実行します。
#import <Foundation/Foundation.h>
typedef void (^CompletionBlock)();
@interface SampleClass:NSObject
- (void)performActionWithCompletion:(CompletionBlock)completionBlock;
@end
@implementation SampleClass
- (void)performActionWithCompletion:(CompletionBlock)completionBlock {
NSLog(@"Action Performed");
completionBlock();
}
@end
int main() {
/*my first program in Objective-C*/
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass performActionWithCompletion:^{
NSLog(@"Completion is called to intimate action is performed.");
}];
return 0;
}
私たちはそれをコンパイルして実行しましょう、それは次の結果を生成します-
2013-09-10 08:13:57.155 demo[284:303] Action Performed
2013-09-10 08:13:57.157 demo[284:303] Completion is called to intimate action is performed.
ブロックは、iOSアプリケーションおよびMac OS Xでさらに使用されます。 そのため、ブロックの使用法を理解することがより重要です。
Objective-Cの番号
Objective-Cプログラミング言語では、int、float、boolなどの基本的なデータ型をオブジェクト形式で保存するために、
Objective-Cは、NSNumberを操作するためのさまざまな方法を提供します。重要な方法を次の表に示します。
| Sr.No. | Method & Description |
|---|---|
| 1 |
+ (NSNumber *)numberWithBool:(BOOL)value 指定された値を含むNSNumberオブジェクトを作成して返し、BOOLとして処理します。 |
| 2 |
+ (NSNumber *)numberWithChar:(char)value 指定された値を含むNSNumberオブジェクトを作成して返し、それを符号付き文字として扱います。 |
| 3 |
+ (NSNumber *)numberWithDouble:(double)value 指定された値を含むNSNumberオブジェクトを作成して返し、それをdoubleとして扱います。 |
| 4 |
+ (NSNumber *)numberWithFloat:(float)value 指定された値を含むNSNumberオブジェクトを作成して返し、floatとして扱います。 |
| 5 |
+ (NSNumber *)numberWithInt:(int)value 指定された値を含むNSNumberオブジェクトを作成して返し、それを符号付きintとして扱います。 |
| 6 |
+ (NSNumber *)numberWithInteger:(NSInteger)value 指定された値を含むNSNumberオブジェクトを作成して返し、NSIntegerとして扱います。 |
| 7 |
受信者の値をBOOLとして返します。 |
| 8 |
受信者の値をcharとして返します。 |
| 9 |
受信者の値をdoubleとして返します。 |
| 10 |
受信者の値をfloatとして返します。 |
| 11 |
NSIntegerとして受信者の値を返します。 |
| 12 |
受信者の値をintとして返します。 |
| 13 |
受信者の値を人間が読める文字列として返します。 |
NSNumberを使用して2つの数値を乗算し、積を返す簡単な例を次に示します。
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (NSNumber* )multiplyA:(NSNumber *)a withB:(NSNumber *)b;
@end
@implementation SampleClass
- (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b {
float number1 = [a floatValue];
float number2 = [b floatValue];
float product = number1 *number2;
NSNumber* result = [NSNumber numberWithFloat:product];
return result;
}
@end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SampleClass* sampleClass = [[SampleClass alloc]init];
NSNumber *a = [NSNumber numberWithFloat:10.5];
NSNumber *b = [NSNumber numberWithFloat:10.0];
NSNumber *result = [sampleClass multiplyA:a withB:b];
NSString *resultString = [result stringValue];
NSLog(@"The product is %@",resultString);
[pool drain];
return 0;
}
プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-14 18:53:40.575 demo[16787] The product is 105
Objective-Cアレイ
Objective-Cプログラミング言語は、*配列*と呼ばれるデータ構造を提供します。これは、同じタイプの要素の固定サイズの順次コレクションを格納できます。 配列はデータのコレクションを格納するために使用されますが、配列を同じタイプの変数のコレクションと考える方が便利な場合がよくあります。
number0、number1、…、number99などの個々の変数を宣言する代わりに、numbersなどの1つの配列変数を宣言し、numbers [0]、numbers [1]、…、numbers [99]を使用して表現します個々の変数。 配列内の特定の要素は、インデックスによってアクセスされます。
すべての配列は、連続したメモリ位置で構成されています。 最下位アドレスは最初の要素に対応し、最上位アドレスは最後の要素に対応します。
配列の宣言
Objective-Cで配列を宣言するために、プログラマーは次のように配列に必要な要素の型と要素の数を指定します-
type arrayName [ arraySize ];
これは「単一次元配列」と呼ばれます。 arraySize はゼロより大きい整数定数でなければならず、 type は任意の有効なObjective-Cデータ型にすることができます。 たとえば、double型の balance という10要素の配列を宣言するには、このステートメントを使用します-
double balance[10];
現在、_balance_は可変配列であり、最大10個のdouble数値を保持するのに十分です。
配列の初期化
あなたはObjective-Cの配列を1つずつ、または次のように単一のステートメントを使用して初期化することができます-
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
中括弧\ {}の間の値の数は、角括弧[]の間の配列に対して宣言する要素の数より大きくすることはできません。 以下は、配列の単一の要素を割り当てるための例です-
配列のサイズを省略すると、初期化を保持するのに十分な大きさの配列が作成されます。 したがって、あなたが書く場合-
double balance[] = {1000.0, 2.0, 3.4, 17.0, 50.0};
前の例で作成したのとまったく同じ配列を作成します。
balance[4] = 50.0;
上記のステートメントは、配列の5番目の要素番号に50.0の値を割り当てます。 すべての配列はベースインデックスとも呼ばれる最初の要素のインデックスとして0を持つため、4番目のインデックスを持つ配列は5番目、つまり最後の要素になります。 以下は、上で説明したのと同じ配列の図的表現です-
配列要素へのアクセス
配列名にインデックスを付けることにより、要素にアクセスします。 これは、配列の名前の後に角かっこ内に要素のインデックスを配置することによって行われます。 たとえば-
double salary = balance[9];
上記のステートメントは、配列から10番目の要素を取得し、その値を給与変数に割り当てます。 以下は、上記の3つの概念すべてを使用する例です。 配列の宣言、割り当て、アクセス-
#import <Foundation/Foundation.h>
int main () {
int n[ 10 ]; /*n is an array of 10 integers*/
int i,j;
/*initialize elements of array n to 0*/
for ( i = 0; i < 10; i++ ) {
n[ i ] = i + 100; /*set element at location i to i + 100*/
}
/*output each array element's value*/
for (j = 0; j < 10; j++ ) {
NSLog(@"Element[%d] = %d\n", j, n[j] );
}
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 01:24:06.669 demo[16508] Element[0] = 100
2013-09-14 01:24:06.669 demo[16508] Element[1] = 101
2013-09-14 01:24:06.669 demo[16508] Element[2] = 102
2013-09-14 01:24:06.669 demo[16508] Element[3] = 103
2013-09-14 01:24:06.669 demo[16508] Element[4] = 104
2013-09-14 01:24:06.669 demo[16508] Element[5] = 105
2013-09-14 01:24:06.669 demo[16508] Element[6] = 106
2013-09-14 01:24:06.669 demo[16508] Element[7] = 107
2013-09-14 01:24:06.669 demo[16508] Element[8] = 108
2013-09-14 01:24:06.669 demo[16508] Element[9] = 109
Objective-Cアレイの詳細
配列はObjective-Cにとって重要であり、多くの詳細が必要です。 Objective-Cプログラマには明らかな配列に関連するいくつかの重要な概念があります-
| Sr.No. | Concept & Description |
|---|---|
| 1 |
Objective-Cは多次元配列をサポートしています。 多次元配列の最も単純な形式は、2次元配列です。 |
| 2 |
インデックスなしで配列の名前を指定することで、関数に配列へのポインタを渡すことができます。 |
| 3 |
Objective-Cでは、関数が配列を返すことができます。 |
| 4 |
インデックスなしで配列名を指定するだけで、配列の最初の要素へのポインタを生成できます。 |
Objective-Cポインター
Objective-Cのポインターは簡単で楽しく学ぶことができます。 一部のObjective-Cプログラミングタスクはポインターを使用してより簡単に実行でき、動的メモリ割り当てなどの他のタスクはポインターを使用しないと実行できません。 したがって、完璧なObjective-Cプログラマーになるには、ポインターを学ぶ必要があります。 簡単で簡単な手順で学習を始めましょう。
ご存じのように、すべての変数はメモリロケーションであり、すべてのメモリロケーションには、メモリ内のアドレスを示すアンパサンド(&)演算子を使用してアクセスできるアドレスが定義されています。 定義された変数のアドレスを出力する次の例を考えてください-
#import <Foundation/Foundation.h>
int main () {
int var1;
char var2[10];
NSLog(@"Address of var1 variable: %x\n", &var1 );
NSLog(@"Address of var2 variable: %x\n", &var2 );
return 0;
}
上記のコードをコンパイルして実行すると、次のような結果が生成されます-
2013-09-13 03:18:45.727 demo[17552] Address of var1 variable: 1c0843fc
2013-09-13 03:18:45.728 demo[17552] Address of var2 variable: 1c0843f0
したがって、メモリアドレスとそのアクセス方法を理解したので、コンセプトの基本は終わりました。 次に、ポインターとは何かを見てみましょう。
ポインターとは
- ポインタ*は、値が別の変数のアドレス、つまりメモリ位置の直接アドレスである変数です。 他の変数や定数と同様に、ポインターを使用して変数アドレスを保存する前に、ポインターを宣言する必要があります。 ポインタ変数宣言の一般的な形式は-
type *var-name;
ここで、 type はポインターの基本型です。有効なObjective-Cデータ型である必要があり、 var-name はポインター変数の名前です。 ポインターの宣言に使用したアスタリスク*は、乗算に使用したものと同じアスタリスクです。 ただし、このステートメントでは、変数をポインターとして指定するためにアスタリスクが使用されています。 有効なポインター宣言は次のとおりです-
int *ip; /*pointer to an integer*/
double *dp; /*pointer to a double*/
float *fp; /*pointer to a float*/
char *ch /*pointer to a character*/
すべてのポインターの値の実際のデータ型は、整数、浮動小数点、文字、またはその他のいずれであっても同じで、メモリアドレスを表す長い16進数です。 異なるデータ型のポインターの唯一の違いは、ポインターが指す変数または定数のデータ型です。
ポインターの使用方法
重要な操作はほとんどなく、非常に頻繁にポインターを使用して行います。 (a)*ポインター変数を定義し、(b)変数のアドレスをポインターに割り当て、(c)がポインター変数で使用可能なアドレスの値に最終的にアクセスします。 これは、オペランドで指定されたアドレスにある変数の値を返す単項演算子**を使用して行われます。 次の例では、これらの操作を利用しています-
#import <Foundation/Foundation.h>
int main () {
int var = 20; /*actual variable declaration*/
int *ip; /*pointer variable declaration*/
ip = &var; /* store address of var in pointer variable*/
NSLog(@"Address of var variable: %x\n", &var );
/*address stored in pointer variable*/
NSLog(@"Address stored in ip variable: %x\n", ip );
/*access the value using the pointer*/
NSLog(@"Value of *ip variable: %d\n", *ip );
return 0;
}
上記のコードをコンパイルして実行すると、次のような結果が生成されます-
2013-09-13 03:20:21.873 demo[24179] Address of var variable: 337ed41c
2013-09-13 03:20:21.873 demo[24179] Address stored in ip variable: 337ed41c
2013-09-13 03:20:21.874 demo[24179] Value of *ip variable: 20
Objective-CのNULLポインター
正確なアドレスが割り当てられていない場合に備えて、ポインタ変数にNULL値を割り当てることを常にお勧めします。 これは、変数宣言時に行われます。 NULLが割り当てられたポインターは、 null ポインターと呼ばれます。
NULLポインターは、いくつかの標準ライブラリで定義されている値がゼロの定数です。 次のプログラムを検討してください-
#import <Foundation/Foundation.h>
int main () {
int *ptr = NULL;
NSLog(@"The value of ptr is : %x\n", ptr );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-13 03:21:19.447 demo[28027] The value of ptr is : 0
ほとんどのオペレーティングシステムでは、アドレス0のメモリにアクセスすることは許可されていません。これは、メモリがオペレーティングシステムによって予約されているためです。 ただし、メモリアドレス0には特別な意味があります。ポインタがアクセス可能なメモリ位置を指すように意図されていないことを通知します。 ただし、慣例により、ポインターにNULL(ゼロ)値が含まれている場合、ポインターは何も指していないと見なされます。
NULLポインタを確認するには、次のようにif文を使用することができます-
if(ptr) /*succeeds if p is not null*/
if(!ptr) /*succeeds if p is null*/
Objective-Cポインターの詳細
ポインターには多くの簡単な概念があり、Objective-Cプログラミングにとって非常に重要です。 次のいくつかの重要なポインタの概念があります。これらは、Objective-Cプログラマには明らかなはずです-
| Sr.No. | Concept & Description |
|---|---|
| 1 |
Objective-C - Pointer arithmetic ポインターで使用できる4つの算術演算子があります:+、-、、- |
| 2 |
Objective-C - Array of pointers 配列を定義して、多数のポインターを保持できます。 |
| 3 |
Objective-C - Pointer to pointer Objective-Cを使用すると、ポインターをポインターに合わせることができます。 |
| 4 |
Passing pointers to functions in Objective-C 参照またはアドレスの両方で引数を渡すと、呼び出された関数によって、呼び出された関数で渡された引数を変更できます。 |
| 5 |
Return pointer from functions in Objective-C Objective-Cでは、関数がローカル変数、静的変数、および動的に割り当てられたメモリへのポインターも返すことができます。 |
Objective-Cの文字列
Objective-Cプログラミング言語の文字列はNSStringを使用して表され、そのサブクラスNSMutableStringは文字列オブジェクトを作成するためのいくつかの方法を提供します。 文字列オブジェクトを作成する最も簡単な方法は、Objective-C @ "…"コンストラクトを使用することです-
NSString *greeting = @"Hello";
文字列の作成と印刷の簡単な例を以下に示します。
#import <Foundation/Foundation.h>
int main () {
NSString *greeting = @"Hello";
NSLog(@"Greeting message: %@\n", greeting );
return 0;
}
上記のコードをコンパイルして実行すると、次のような結果が生成されます-
2013-09-11 01:21:39.922 demo[23926] Greeting message: Hello
Objective-Cは、文字列を操作するための幅広い方法をサポートしています-
| Sr.No. | Method & Purpose |
|---|---|
| 1 |
レシーバーの大文字表記を返します。 |
| 2 |
指定された配列位置の文字を返します。 |
| 3 |
受信者のテキストの浮動小数点値をdoubleとして返します。 |
| 4 |
受信者のテキストの浮動小数点値をfloatとして返します。 |
| 5 |
特定の文字列がレシーバーの開始文字に一致するかどうかを示すブール値を返します。 |
| 6 |
指定された文字列が受信者の終了文字と一致するかどうかを示すブール値を返します。 |
| 7 |
指定されたフォーマット文字列をテンプレートとして使用して初期化されたNSStringオブジェクトを返します。テンプレートには、残りの引数値が代入されます。 |
| 8 |
受信者のテキストのNSInteger値を返します。 |
| 9 |
Unicodeベースのリテラル比較を使用して、指定された文字列がレシーバーと等しいかどうかを示すブール値を返します。 |
| 10 |
レシーバーのUnicode文字の数を返します。 |
| 11 |
レシーバーの小文字表現を返します。 |
| 12 |
レシーバー内で特定の文字列が最初に現れる範囲を検索して返します。 |
| 13 |
指定されたフォーマット文字列と次の引数から構築された文字列を受信機に追加することにより作成された文字列を返します。 |
| 14 |
指定された文字セットに含まれるレシーバー文字の両端から削除して作成された新しい文字列を返します。 |
| 15 |
指定されたインデックスの文字から最後までのレシーバの文字を含む新しい文字列を返します。 |
次の例では、上記の機能のいくつかを利用しています-
#import <Foundation/Foundation.h>
int main () {
NSString* str1 = @"Hello";
NSString *str2 = @"World";
NSString *str3;
int len ;
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
/*uppercase string*/
str3 = [str2 uppercaseString];
NSLog(@"Uppercase String : %@\n", str3 );
/*concatenates str1 and str2*/
str3 = [str1 stringByAppendingFormat:@"World"];
NSLog(@"Concatenated string: %@\n", str3 );
/*total length of str3 after concatenation*/
len = [str3 length];
NSLog(@"Length of Str3 : %d\n", len );
/*InitWithFormat*/
str3 = [[NSString alloc] initWithFormat:@"%@ %@",str1,str2];
NSLog(@"Using initWithFormat: %@\n", str3 );
[pool drain];
return 0;
}
上記のコードをコンパイルして実行すると、次のような結果が生成されます-
2013-09-11 01:15:45.069 demo[30378] Uppercase String : WORLD
2013-09-11 01:15:45.070 demo[30378] Concatenated string: HelloWorld
2013-09-11 01:15:45.070 demo[30378] Length of Str3 : 10
2013-09-11 01:15:45.070 demo[30378] Using initWithFormat: Hello World
Objective-C NSString関連のメソッドの完全なリストは、https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSStringl [NSString Class Reference。]にあります。
Objective-Cの構造
Objective-C配列を使用すると、同じ種類の複数のデータ項目を保持できる変数のタイプを定義できますが、 structure は、Objective-Cプログラミングで使用できる別のユーザー定義データ型で、異なる種類のデータ項目を組み合わせることができます。
構造はレコードを表すために使用されます。図書館で本を追跡したいとします。 あなたは、各本に関する次の属性を追跡することができます-
- タイトル
- 著者
- 件名
- ブックID
構造の定義
構造を定義するには、 struct ステートメントを使用する必要があります。 structステートメントは、プログラムに複数のメンバーを持つ新しいデータ型を定義します。 構造体ステートメントの形式は以下に示されています-
struct [structure tag] {
member definition;
member definition;
...
member definition;
} [one or more structure variables];
- 構造タグ*はオプションであり、各メンバー定義はint iなどの通常の変数定義です。またはfloat f;または他の有効な変数定義。 構造の定義の最後で、最後のセミコロンの前に、1つ以上の構造変数を指定できますが、これはオプションです。 ここにあなたが本の構造を宣言する方法があります-
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
} book;
構造体メンバーへのアクセス
構造体のメンバーにアクセスするには、* memberアクセス演算子(。)を使用します。 メンバーアクセス演算子は、構造変数名とアクセスする構造メンバーの間のピリオドとしてコーディングされます。 *struct キーワードを使用して、構造タイプの変数を定義します。 以下は、構造の使用法を説明する例です-
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
int main() {
struct Books Book1; /*Declare Book1 of type Book*/
struct Books Book2; /*Declare Book2 of type Book*/
/*book 1 specification*/
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/*book 2 specification*/
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
/*print Book1 info*/
NSLog(@"Book 1 title : %@\n", Book1.title);
NSLog(@"Book 1 author : %@\n", Book1.author);
NSLog(@"Book 1 subject : %@\n", Book1.subject);
NSLog(@"Book 1 book_id : %d\n", Book1.book_id);
/*print Book2 info*/
NSLog(@"Book 2 title : %@\n", Book2.title);
NSLog(@"Book 2 author : %@\n", Book2.author);
NSLog(@"Book 2 subject : %@\n", Book2.subject);
NSLog(@"Book 2 book_id : %d\n", Book2.book_id);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 04:20:07.947 demo[20591] Book 1 title : Objective-C Programming
2013-09-14 04:20:07.947 demo[20591] Book 1 author : Nuha Ali
2013-09-14 04:20:07.947 demo[20591] Book 1 subject : Objective-C Programming Tutorial
2013-09-14 04:20:07.947 demo[20591] Book 1 book_id : 6495407
2013-09-14 04:20:07.947 demo[20591] Book 2 title : Telecom Billing
2013-09-14 04:20:07.947 demo[20591] Book 2 author : Zara Ali
2013-09-14 04:20:07.947 demo[20591] Book 2 subject : Telecom Billing Tutorial
2013-09-14 04:20:07.947 demo[20591] Book 2 book_id : 6495700
関数の引数としての構造
他の変数またはポインターを渡すのと非常によく似た方法で、構造体を関数の引数として渡すことができます。 上記の例でアクセスしたのと同様の方法で構造変数にアクセスします-
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
@interface SampleClass:NSObject
/*function declaration*/
- (void) printBook:( struct Books) book ;
@end
@implementation SampleClass
- (void) printBook:( struct Books) book {
NSLog(@"Book title : %@\n", book.title);
NSLog(@"Book author : %@\n", book.author);
NSLog(@"Book subject : %@\n", book.subject);
NSLog(@"Book book_id : %d\n", book.book_id);
}
@end
int main() {
struct Books Book1; /*Declare Book1 of type Book*/
struct Books Book2; /*Declare Book2 of type Book*/
/*book 1 specification*/
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/*book 2 specification*/
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
SampleClass *sampleClass = [[SampleClass alloc]init];
/*print Book1 info*/
[sampleClass printBook: Book1];
/*Print Book2 info*/
[sampleClass printBook: Book2];
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 04:34:45.725 demo[8060] Book title : Objective-C Programming
2013-09-14 04:34:45.725 demo[8060] Book author : Nuha Ali
2013-09-14 04:34:45.725 demo[8060] Book subject : Objective-C Programming Tutorial
2013-09-14 04:34:45.725 demo[8060] Book book_id : 6495407
2013-09-14 04:34:45.725 demo[8060] Book title : Telecom Billing
2013-09-14 04:34:45.725 demo[8060] Book author : Zara Ali
2013-09-14 04:34:45.725 demo[8060] Book subject : Telecom Billing Tutorial
2013-09-14 04:34:45.725 demo[8060] Book book_id : 6495700
構造体へのポインター
次のように他の変数へのポインタを定義するのと非常に似た方法で構造体へのポインタを定義できます-
struct Books *struct_pointer;
これで、上記で定義したポインター変数に構造変数のアドレスを保存できます。 構造変数のアドレスを見つけるには、次のように構造の名前の前に&演算子を配置します-
struct_pointer = &Book1;
その構造へのポインタを使用して構造のメンバーにアクセスするには、次のように→演算子を使用する必要があります-
struct_pointer->title;
構造ポインタを使用して上記の例を書き直してみましょう。これが概念を理解しやすくなることを願っています-
#import <Foundation/Foundation.h>
struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
};
@interface SampleClass:NSObject
/*function declaration*/
- (void) printBook:( struct Books *) book ;
@end
@implementation SampleClass
- (void) printBook:( struct Books *) book {
NSLog(@"Book title : %@\n", book->title);
NSLog(@"Book author : %@\n", book->author);
NSLog(@"Book subject : %@\n", book->subject);
NSLog(@"Book book_id : %d\n", book->book_id);
}
@end
int main() {
struct Books Book1; /*Declare Book1 of type Book*/
struct Books Book2; /*Declare Book2 of type Book*/
/*book 1 specification*/
Book1.title = @"Objective-C Programming";
Book1.author = @"Nuha Ali";
Book1.subject = @"Objective-C Programming Tutorial";
Book1.book_id = 6495407;
/*book 2 specification*/
Book2.title = @"Telecom Billing";
Book2.author = @"Zara Ali";
Book2.subject = @"Telecom Billing Tutorial";
Book2.book_id = 6495700;
SampleClass *sampleClass = [[SampleClass alloc]init];
/*print Book1 info by passing address of Book1*/
[sampleClass printBook:&Book1];
/*print Book2 info by passing address of Book2*/
[sampleClass printBook:&Book2];
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 04:38:13.942 demo[20745] Book title : Objective-C Programming
2013-09-14 04:38:13.942 demo[20745] Book author : Nuha Ali
2013-09-14 04:38:13.942 demo[20745] Book subject : Objective-C Programming Tutorial
2013-09-14 04:38:13.942 demo[20745] Book book_id : 6495407
2013-09-14 04:38:13.942 demo[20745] Book title : Telecom Billing
2013-09-14 04:38:13.942 demo[20745] Book author : Zara Ali
2013-09-14 04:38:13.942 demo[20745] Book subject : Telecom Billing Tutorial
2013-09-14 04:38:13.942 demo[20745] Book book_id : 6495700
ビットフィールド
ビットフィールドを使用すると、構造体にデータをパックできます。 これは、メモリまたはデータストレージが貴重な場合に特に便利です。 典型的な例-
- 複数のオブジェクトを機械語にパックします。 e.g. 1ビットフラグは圧縮できます。
- 外部ファイル形式の読み取り-非標準のファイル形式を読み取ることができます。 E.g. 9ビット整数。
Objective-Cでは、変数の後に:bit lengthを追加することにより、構造定義でこれを行うことができます。 たとえば-
struct packed_struct {
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int f4:1;
unsigned int type:4;
unsigned int my_int:9;
} pack;
ここで、packed_structには、4つの1ビットフラグf1..f3、4ビットタイプ、9ビットmy_intの6つのメンバーが含まれています。
Objective-Cは、フィールドの最大長がコンピューターの整数ワード長以下である場合、上記のビットフィールドを可能な限りコンパクトに自動的にパックします。 そうでない場合、一部のコンパイラはフィールドのメモリオーバーラップを許可し、他のコンパイラは次の単語の次のフィールドを保存します。
Objective-Cプリプロセッサ
- Objective-Cプリプロセッサ*はコンパイラの一部ではありませんが、コンパイルプロセスの別のステップです。 簡単に言えば、Objective-Cプリプロセッサーは単なるテキスト置換ツールであり、実際のコンパイルの前に必要な前処理を行うようコンパイラーに指示します。 Objective-CプリプロセッサをOCPPと呼びます。
すべてのプリプロセッサコマンドは、ポンド記号(#)で始まります。 最初の非空白文字である必要があります。読みやすくするために、プリプロセッサディレクティブは最初の列から開始する必要があります。 次のセクションでは、すべての重要なプリプロセッサディレクティブをリストします-
| Sr.No. | Directive & Description |
|---|---|
| 1 |
#define プリプロセッサマクロを置き換えます |
| 2 |
#include 別のファイルから特定のヘッダーを挿入します |
| 3 |
#undef プリプロセッサマクロの定義を解除します |
| 4 |
#ifdef このマクロが定義されている場合、trueを返します |
| 5 |
#ifndef このマクロが定義されていない場合はtrueを返します |
| 6 |
#if コンパイル時の条件が真かどうかをテストします |
| 7 |
#else
|
| 8 |
#elif
|
| 9 |
#endif プリプロセッサー条件付きを終了します |
| 10 |
#error エラーメッセージを標準エラー出力に出力します |
| 11 |
#pragma 標準化された方法を使用して、コンパイラに特別なコマンドを発行します |
プリプロセッサの例
以下の例を分析して、さまざまなディレクティブを理解してください。
#define MAX_ARRAY_LENGTH 20
このディレクティブは、OCPPにMAX_ARRAY_LENGTHのインスタンスを20に置き換えるように指示します。 定数に_#define_を使用して、読みやすくします。
#import <Foundation/Foundation.h>
#include "myheader.h"
これらのディレクティブは、OCPPに Foundation Framework からFoundation.hを取得し、現在のソースファイルにテキストを追加するように指示します。 次の行は、OCPPにローカルディレクトリから myheader.h を取得し、現在のソースファイルにコンテンツを追加するように指示します。
#undef FILE_SIZE
#define FILE_SIZE 42
これにより、既存のFILE_SIZEの定義を解除し、42として定義するようOCPPに指示します。
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
これは、MESSAGEがまだ定義されていない場合にのみ、OCPPにMESSAGEを定義するように指示します。
#ifdef DEBUG
/*Your debugging statements here*/
#endif
これは、DEBUGが定義されている場合、囲まれたステートメントを処理するようにOCPPに指示します。 これは、コンパイル時にgccコンパイラに_-DDEBUG_フラグを渡す場合に便利です。 これによりDEBUGが定義されるため、コンパイル中にオンザフライでデバッグをオンまたはオフにできます。
定義済みマクロ
ANSI Cは多くのマクロを定義しています。 それぞれをプログラミングで使用できますが、事前定義されたマクロを直接変更しないでください。
| Sr.No. | Macro & Description |
|---|---|
| 1 |
DATE 「MMM DD YYYY」形式の文字リテラルとしての現在の日付 |
| 2 |
TIME 「HH:MM:SS」形式の文字リテラルとしての現在時刻 |
| 3 |
FILE これには、現在のファイル名が文字列リテラルとして含まれています。 |
| 4 |
LINE これには、10進定数として現在の行番号が含まれます。 |
| 5 |
STDC コンパイラがANSI標準に準拠する場合、1として定義されます。 |
次の例を試してみましょう-
#import <Foundation/Foundation.h>
int main() {
NSLog(@"File :%s\n", __FILE__ );
NSLog(@"Date :%s\n", __DATE__ );
NSLog(@"Time :%s\n", __TIME__ );
NSLog(@"Line :%d\n", __LINE__ );
NSLog(@"ANSI :%d\n", __STDC__ );
return 0;
}
ファイル main.m の上記のコードがコンパイルされ実行されると、次の結果が生成されます-
2013-09-14 04:46:14.859 demo[20683] File :main.m
2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013
2013-09-14 04:46:14.859 demo[20683] Time :04:46:14
2013-09-14 04:46:14.859 demo[20683] Line :8
2013-09-14 04:46:14.859 demo[20683] ANSI :1
プリプロセッサ演算子
Objective-Cプリプロセッサは、マクロの作成に役立つ次の演算子を提供します-
マクロの継続(\)
通常、マクロは1行に含める必要があります。 マクロ継続演算子は、1行では長すぎるマクロを継続するために使用されます。 たとえば-
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
文字列化(#)
文字列化または番号記号演算子( '#')は、マクロ定義内で使用されると、マクロパラメーターを文字列定数に変換します。 この演算子は、指定された引数またはパラメーターリストを持つマクロでのみ使用できます。 たとえば-
#import <Foundation/Foundation.h>
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 05:46:14.859 demo[20683] Carole and Debra: We love you!
トークンの貼り付け(##)
マクロ定義内のトークン貼り付け演算子(##)は、2つの引数を組み合わせます。 マクロ定義内の2つの別個のトークンを単一のトークンに結合できます。 たとえば-
#import <Foundation/Foundation.h>
#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 05:48:14.859 demo[20683] token34 = 40
この例は、プリプロセッサから次の実際の出力をもたらすため、それが起こった方法-
NSLog (@"token34 = %d", token34);
この例では、token ## nのtoken34への連結を示しています。ここでは、 stringize と token-pasting の両方を使用しています。
defined()演算子
プリプロセッサの defined 演算子は、定数式で使用され、#defineを使用して識別子が定義されているかどうかを判断します。 指定された識別子が定義されている場合、値はtrue(ゼロ以外)です。 シンボルが定義されていない場合、値はfalse(ゼロ)です。 定義された演算子は次のように指定されます-
#import <Foundation/Foundation.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
NSLog(@"Here is the message: %s\n", MESSAGE);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 05:48:19.859 demo[20683] Here is the message: You wish!
パラメータ化されたマクロ
OCPPの強力な機能の1つは、パラメーター化されたマクロを使用して機能をシミュレートする機能です。 たとえば、次のように数値を二乗するコードがあります-
int square(int x) {
return x *x;
}
次のようにマクロを使用して上記のコードを書き換えることができます-
#define square(x) ((x)* (x))
引数を持つマクロは、使用する前に*#define *ディレクティブを使用して定義する必要があります。 引数リストは括弧で囲まれ、マクロ名の直後になければなりません。 マクロ名と左括弧の間にスペースは使用できません。 たとえば-
#import <Foundation/Foundation.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20
Objective-C Typedef
Objective-Cプログラミング言語は、 typedef というキーワードを提供します。このキーワードを使用して、タイプに新しい名前を付けることができます。 以下は、1バイトの数字に対して用語 BYTE を定義する例です-
typedef unsigned char BYTE;
このタイプ定義の後、識別子BYTEは、タイプ* unsigned charの省略形として使用できます。例:*。
BYTE b1, b2;
慣例により、これらの定義には大文字が使用され、ユーザーに型名は実際には記号の略語であることを思い出させますが、次のように小文字を使用できます-
typedef unsigned char byte;
*typedef* を使用して、ユーザー定義のデータ型にも名前を付けることができます。 たとえば、構造体でtypedefを使用して新しいデータ型を定義し、そのデータ型を使用して次のように構造体変数を直接定義できます-
#import <Foundation/Foundation.h>
typedef struct Books {
NSString *title;
NSString *author;
NSString *subject;
int book_id;
} Book;
int main() {
Book book;
book.title = @"Objective-C Programming";
book.author = @"finddevguides";
book.subject = @"Programming tutorial";
book.book_id = 100;
NSLog( @"Book title : %@\n", book.title);
NSLog( @"Book author : %@\n", book.author);
NSLog( @"Book subject : %@\n", book.subject);
NSLog( @"Book Id : %d\n", book.book_id);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-12 12:21:53.745 demo[31183] Book title : Objective-C Programming
2013-09-12 12:21:53.745 demo[31183] Book author : finddevguides
2013-09-12 12:21:53.745 demo[31183] Book subject : Programming tutorial
2013-09-12 12:21:53.745 demo[31183] Book Id : 100
typedef vs #define
#define *はObjective-Cディレクティブです。これは、 *typedef に似ていますが、以下の違いがあるさまざまなデータ型のエイリアスを定義するためにも使用されます-
- typedef は、タイプにのみシンボリック名を与えることに制限されていますが、*#define *は、1をONEなどとして定義できるように、値のエイリアスを定義するためにも使用できます。
- typedef の解釈はコンパイラによって実行され、*#define *ステートメントはプリプロセッサによって処理されます。
以下は、#defineの最も簡単な使用法です-
#import <Foundation/Foundation.h>
#define TRUE 1
#define FALSE 0
int main( ) {
NSLog( @"Value of TRUE : %d\n", TRUE);
NSLog( @"Value of FALSE : %d\n", FALSE);
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-12 12:23:37.993 demo[5160] Value of TRUE : 1
2013-09-12 12:23:37.994 demo[5160] Value of FALSE : 0
Objective-Cタイプの鋳造
型キャストは、変数をあるデータ型から別のデータ型に変換する方法です。 たとえば、long値を単純な整数に格納する場合は、cast long to intと入力できます。 次のように*キャスト演算子*を使用して明示的に値を1つのタイプから別のタイプに変換できます-
(type_name) expression
Objective-Cでは、通常、浮動小数点演算にCGFloatを使用します。これは、32ビットの場合はフロートの基本型から、64ビットの場合はdoubleから派生します。 キャスト演算子が別の整数変数の除算を浮動小数点演算として実行する次の例を考えてください-
#import <Foundation/Foundation.h>
int main() {
int sum = 17, count = 5;
CGFloat mean;
mean = (CGFloat) sum/count;
NSLog(@"Value of mean : %f\n", mean );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-11 01:35:40.047 demo[20634] Value of mean : 3.400000
ここで、キャスト演算子は除算よりも優先されるため、 sum の値は最初に double 型に変換され、最後にcountで除算されてdouble値が生成されることに注意してください。
型変換は、コンパイラによって自動的に実行される暗黙的なものにすることも、* cast演算子*を使用して明示的に指定することもできます。 型変換が必要な場合は、キャスト演算子を使用することをお勧めします。
整数プロモーション
整数プロモーションは、整数型の値が int または unsigned int よりも小さい値が int または unsigned int に変換されるプロセスです。 intに文字を追加する例を考えてみましょう-
#import <Foundation/Foundation.h>
int main() {
int i = 17;
char c = 'c'; /*ascii value is 99*/
int sum;
sum = i + c;
NSLog(@"Value of sum : %d\n", sum );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-11 01:38:28.492 demo[980] Value of sum : 116
ここで、コンパイラは整数の昇格を行い、実際の加算操作を実行する前に 'c’の値をasciiに変換しているため、sumの値は116になります。
通常の算術変換
- 通常の算術変換*は、それらの値を共通の型にキャストするために暗黙的に実行されます。 コンパイラは、最初に_integerプロモーション_を実行します。オペランドがまだ異なる型を持っている場合、それらは次の階層で最高に表示される型に変換されます-
通常の算術変換は、代入演算子に対しても、論理演算子&&および||に対しても実行されません。 私たちは概念を理解するために次の例を取りましょう-
#import <Foundation/Foundation.h>
int main() {
int i = 17;
char c = 'c'; /*ascii value is 99*/
CGFloat sum;
sum = i + c;
NSLog(@"Value of sum : %f\n", sum );
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-11 01:41:39.192 demo[15351] Value of sum : 116.000000
ここで、最初のcは整数に変換されますが、最終値はfloatであるため、通常の算術変換が適用され、コンパイラーはiとcをfloatに変換し、それらを加算してfloat結果を生成することを理解するのは簡単です。
Objective-Cログ処理
NSLogメソッド
ログを印刷するには、Hello Worldの例で使用したObjective-Cプログラミング言語のNSLogメソッドを使用します。
「Hello World」という言葉を出力する簡単なコードを見てみましょう-
#import <Foundation/Foundation.h>
int main() {
NSLog(@"Hello, World! \n");
return 0;
}
これで、プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-16 00:32:50.888 demo[16669] Hello, World!
Liveアプリでログを無効にする
NSLogsはアプリケーションで使用するため、デバイスのログに出力されますが、ライブビルドでログを出力するのは適切ではありません。 したがって、ログの印刷にはタイプ定義を使用し、以下に示すように使用できます。
#import <Foundation/Foundation.h>
#if DEBUG == 0
#define DebugLog(...)
#elif DEBUG == 1
#define DebugLog(...) NSLog(__VA_ARGS__)
#endif
int main() {
DebugLog(@"Debug log, our custom addition gets \
printed during debug only" );
NSLog(@"NSLog gets printed always" );
return 0;
}
さて、デバッグモードでプログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-11 02:47:07.723 demo[618] Debug log, our custom addition gets printed during debug only
2013-09-11 02:47:07.723 demo[618] NSLog gets printed always
リリースモードでプログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-11 02:47:45.248 demo[3158] NSLog gets printed always
Objective-Cエラー処理
Objective-Cプログラミングでは、* Foundationフレームワークで使用可能なNSErrorクラスでエラー処理が提供されます。*
NSErrorオブジェクトは、エラーコードまたはエラー文字列のみを使用した場合よりも豊富で拡張可能なエラー情報をカプセル化します。 NSErrorオブジェクトのコア属性は、エラードメイン(文字列で表される)、ドメイン固有のエラーコード、およびアプリケーション固有の情報を含むユーザー情報辞書です。
NSError
Objective-CプログラムはNSErrorオブジェクトを使用して、ユーザーに通知する必要があるランタイムエラーに関する情報を伝えます。 ほとんどの場合、プログラムはこのエラー情報をダイアログまたはシートに表示します。 ただし、情報を解釈して、ユーザーにエラーからの回復を試みるか、エラーの修正を試みることもできます。
NSErrorオブジェクトは-
- ドメイン-エラードメインは、事前定義されたNSErrorドメインのいずれかであるか、カスタムドメインを記述する任意の文字列であり、ドメインがnilであってはなりません。
- コード-エラーのエラーコード。
- ユーザー情報-エラーおよびuserInfoのuserInfo辞書はnilである可能性があります。
次の例は、カスタムエラーを作成する方法を示しています
NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
NSString *desc = NSLocalizedString(@"Unable to complete the process", @"");
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
NSError *error = [NSError errorWithDomain:domain code:-101 userInfo:userInfo];
これは、ポインタへの参照として渡される上記のエラーサンプルの完全なコードです-
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr;
@end
@implementation SampleClass
-(NSString *) getEmployeeNameForID:(int) id withError:(NSError **)errorPtr {
if(id == 1) {
return @"Employee Test Name";
} else {
NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
NSString *desc =@"Unable to complete the process";
NSDictionary *userInfo = [[NSDictionary alloc]
initWithObjectsAndKeys:desc,
@"NSLocalizedDescriptionKey",NULL];
*errorPtr = [NSError errorWithDomain:domain code:-101
userInfo:userInfo];
return @"";
}
}
@end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SampleClass* sampleClass = [[SampleClass alloc]init];
NSError *error = nil;
NSString *name1 = [sampleClass getEmployeeNameForID:1 withError:&error];
if(error) {
NSLog(@"Error finding Name1: %@",error);
} else {
NSLog(@"Name1: %@",name1);
}
error = nil;
NSString *name2 = [sampleClass getEmployeeNameForID:2 withError:&error];
if(error) {
NSLog(@"Error finding Name2: %@",error);
} else {
NSLog(@"Name2: %@",name2);
}
[pool drain];
return 0;
}
上記の例では、idが1の場合、名前を返します。それ以外の場合、ユーザー定義のエラーオブジェクトを設定します。
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-14 18:01:00.809 demo[27632] Name1: Employee Test Name
2013-09-14 18:01:00.809 demo[27632] Error finding Name2: Unable to complete the process
コマンドライン引数
実行時にコマンドラインからObjective-Cプログラムにいくつかの値を渡すことができます。 これらの値は*コマンドライン引数*と呼ばれ、特にコード内でこれらの値をハードコーディングする代わりに外部からプログラムを制御する場合、プログラムにとって重要です。
コマンドライン引数はmain()関数の引数を使用して処理されます。 argc は渡された引数の数を指し、 argv [] はプログラムに渡された各引数を指すポインター配列です。 以下は、コマンドラインから提供された引数があるかどうかをチェックし、それに応じてアクションを取る簡単な例です-
#import <Foundation/Foundation.h>
int main( int argc, char *argv[] ) {
if( argc == 2 ) {
NSLog(@"The argument supplied is %s\n", argv[1]);
} else if( argc > 2 ) {
NSLog(@"Too many arguments supplied.\n");
} else {
NSLog(@"One argument expected.\n");
}
}
上記のコードをコンパイルして、「testing」などの1つの引数で実行すると、次の結果が生成されます。
2013-09-13 03:01:17.333 demo[7640] The argument supplied is testing
上記のコードが、testing1とtesting2などの2つの引数を使用してコンパイルおよび実行されると、次の結果が生成されます。
2013-09-13 03:01:18.333 demo[7640] Too many arguments supplied.
引数を渡さずに上記のコードをコンパイルして実行すると、次の結果が生成されます。
2013-09-13 03:01:18.333 demo[7640] One argument expected
*argv [0]* はプログラム自体の名前を保持し、 *argv [1]* は指定された最初のコマンドライン引数へのポインターであり、* argv [n]は最後の引数であることに注意してください。 引数が指定されない場合、argcは1になります。引数が1つ渡されると、 *argc* は2に設定されます。
すべてのコマンドライン引数をスペースで区切って渡しますが、引数自体にスペースがある場合は、二重引用符 ""または単一引用符 で囲んで引数を渡すことができます。 上記の例をもう一度書き直して、プログラム名を出力し、二重引用符で囲んでコマンドライン引数を渡します-
#import <Foundation/Foundation.h>
int main( int argc, char *argv[] ) {
NSLog(@"Program name %s\n", argv[0]);
if( argc == 2 ) {
NSLog(@"The argument supplied is %s\n", argv[1]);
} else if( argc > 2 ) {
NSLog(@"Too many arguments supplied.\n");
} else {
NSLog(@"One argument expected.\n");
}
return 0;
}
上記のコードを、スペースで区切られた単一の引数を使用してコンパイルおよび実行しますが、二重引用符で囲んで「Testing1 Testing2」と言うと、次の結果が生成されます。
2017-11-30 06:36:59.081 main[71010] Program name main
2017-11-30 06:36:59.082 main[71010] One argument expected.
Objective-Cのクラスとオブジェクト
Objective-Cプログラミング言語の主な目的は、オブジェクト指向をCプログラミング言語に追加することです。クラスは、オブジェクト指向プログラミングをサポートするObjective-Cの中心的な機能であり、ユーザー定義型と呼ばれます。
クラスはオブジェクトの形式を指定するために使用され、データ表現とそのデータを1つのきれいなパッケージに操作するためのメソッドを組み合わせます。 クラス内のデータとメソッドは、クラスのメンバーと呼ばれます。
Objective-Cの特性
- クラスは、2つの異なるセクション、つまり @ interface と @ implementation で定義されています。
- ほとんどすべてがオブジェクトの形式です。
- オブジェクトはメッセージを受信し、オブジェクトは多くの場合受信者と呼ばれます。
- オブジェクトにはインスタンス変数が含まれます。
- オブジェクトとインスタンス変数にはスコープがあります。
- クラスはオブジェクトの実装を隠します。
- プロパティは、他のクラスのクラスインスタンス変数へのアクセスを提供するために使用されます。
Objective-Cクラスの定義
クラスを定義するときには、データ型の設計図を定義します。 これは実際にはデータを定義しませんが、クラス名が何を意味するのか、つまりクラスのオブジェクトが何を構成するのか、そしてそのようなオブジェクトに対して実行できる操作は定義します。
クラス定義は、キーワード @ interface で始まり、その後にインターフェース(クラス)名が続きます。クラス本体は、中括弧のペアで囲まれています。 Objective-Cでは、すべてのクラスは NSObject という基本クラスから派生しています。 これは、すべてのObjective-Cクラスのスーパークラスです。 メモリの割り当てや初期化などの基本的な方法を提供します。 たとえば、次のようにキーワード class を使用してBoxデータ型を定義しました-
@interface Box:NSObject {
//Instance variables
double length; //Length of a box
double breadth; //Breadth of a box
}
@property(nonatomic, readwrite) double height; //Property
@end
インスタンス変数はプライベートであり、クラス実装内でのみアクセス可能です。
Objective-Cオブジェクトの割り当てと初期化
クラスはオブジェクトの設計図を提供するため、基本的にオブジェクトはクラスから作成されます。 基本型の変数を宣言するのとまったく同じ種類の宣言でクラスのオブジェクトを宣言します。 次のステートメントは、クラスBoxの2つのオブジェクトを宣言します-
Box box1 = [[Box alloc]init]; //Create box1 object of type Box
Box box2 = [[Box alloc]init]; //Create box2 object of type Box
オブジェクトbox1とbox2の両方に、データメンバーの独自のコピーがあります。
データメンバーへのアクセス
クラスのオブジェクトのプロパティには、直接メンバーアクセス演算子(。)を使用してアクセスできます。 物事を明確にするために次の例を試してみましょう-
#import <Foundation/Foundation.h>
@interface Box:NSObject {
double length; //Length of a box
double breadth; //Breadth of a box
double height; //Height of a box
}
@property(nonatomic, readwrite) double height; //Property
-(double) volume;
@end
@implementation Box
@synthesize height;
-(id)init {
self = [super init];
length = 1.0;
breadth = 1.0;
return self;
}
-(double) volume {
return length*breadth*height;
}
@end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Box* box1 = [[Box alloc]init]; //Create box1 object of type Box
Box *box2 = [[Box alloc]init]; //Create box2 object of type Box
double volume = 0.0; //Store the volume of a box here
//box 1 specification
box1.height = 5.0;
//box 2 specification
box2.height = 10.0;
//volume of box 1
volume = [box1 volume];
NSLog(@"Volume of Box1 : %f", volume);
//volume of box 2
volume = [box2 volume];
NSLog(@"Volume of Box2 : %f", volume);
[pool drain];
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-22 21:25:33.314 ClassAndObjects[387:303] Volume of Box1 : 5.000000
2013-09-22 21:25:33.316 ClassAndObjects[387:303] Volume of Box2 : 10.000000
プロパティ
クラスのインスタンス変数にクラスの外部からアクセスできるようにするために、Objective-Cにプロパティが導入されています。
- プロパティは @ property で始まります。これはキーワードです
- その後に、非アトミックまたはアトミック、読み取り書き込みまたは読み取り専用、および強い、unsafe_unretainedまたは弱いアクセス指定子が続きます。 これは、変数のタイプによって異なります。 任意のポインタータイプに対して、strong、unsafe_unretainedまたはweakを使用できます。 他のタイプについても同様に、readwriteまたはreadonlyを使用できます。
- これには、変数のデータ型が続きます。
- 最後に、セミコロンで終了するプロパティ名があります。
- 実装クラスにsynthesticステートメントを追加できます。 しかし、最新のXCodeでは、合成部分はXCodeによって管理されているため、synthesticステートメントを含める必要はありません。
クラスのインスタンス変数にアクセスできるプロパティでのみ可能です。 実際には、プロパティに対して内部的にgetterおよびsetterメソッドが作成されます。
たとえば、プロパティ @ property(nonatomic、readonly)BOOL isDone があるとします。 ボンネットの下には、以下に示すように作成されたセッターとゲッターがあります。
-(void)setIsDone(BOOL)isDone;
-(BOOL)isDone;
Objective-Cの継承
オブジェクト指向プログラミングで最も重要な概念の1つは、継承の概念です。 継承を使用すると、別のクラスの観点からクラスを定義でき、アプリケーションの作成と保守が容易になります。 これにより、コード機能を再利用して実装時間を短縮することもできます。
クラスを作成するとき、プログラマは完全に新しいデータメンバーとメンバー関数を記述する代わりに、新しいクラスが既存のクラスのメンバーを継承するように指定できます。 この既存のクラスは base クラスと呼ばれ、新しいクラスは derived クラスと呼ばれます。
継承の概念は、 is a 関係を実装します。 たとえば、哺乳類IS-A動物、犬IS-A哺乳類、したがって犬IS-A動物などです。
基本クラスと派生クラス
Objective-Cでは、マルチレベルの継承のみが許可されます。つまり、ベースクラスは1つしか持てませんが、マルチレベルの継承は許可されます。 Objective-Cのすべてのクラスは、スーパークラス NSObject から派生しています。
@interface derived-class: base-class
次のように、基本クラス Person とその派生クラス Employee を考えます-
#import <Foundation/Foundation.h>
@interface Person : NSObject {
NSString *personName;
NSInteger personAge;
}
- (id)initWithName:(NSString *)name andAge:(NSInteger)age;
- (void)print;
@end
@implementation Person
- (id)initWithName:(NSString *)name andAge:(NSInteger)age {
personName = name;
personAge = age;
return self;
}
- (void)print {
NSLog(@"Name: %@", personName);
NSLog(@"Age: %ld", personAge);
}
@end
@interface Employee : Person {
NSString *employeeEducation;
}
- (id)initWithName:(NSString *)name andAge:(NSInteger)age
andEducation:(NSString *)education;
- (void)print;
@end
@implementation Employee
- (id)initWithName:(NSString *)name andAge:(NSInteger)age
andEducation: (NSString *)education {
personName = name;
personAge = age;
employeeEducation = education;
return self;
}
- (void)print {
NSLog(@"Name: %@", personName);
NSLog(@"Age: %ld", personAge);
NSLog(@"Education: %@", employeeEducation);
}
@end
int main(int argc, const char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Base class Person Object");
Person *person = [[Person alloc]initWithName:@"Raj" andAge:5];
[person print];
NSLog(@"Inherited Class Employee Object");
Employee *employee = [[Employee alloc]initWithName:@"Raj"
andAge:5 andEducation:@"MBA"];
[employee print];
[pool drain];
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-22 21:20:09.842 Inheritance[349:303] Base class Person Object
2013-09-22 21:20:09.844 Inheritance[349:303] Name: Raj
2013-09-22 21:20:09.844 Inheritance[349:303] Age: 5
2013-09-22 21:20:09.845 Inheritance[349:303] Inherited Class Employee Object
2013-09-22 21:20:09.845 Inheritance[349:303] Name: Raj
2013-09-22 21:20:09.846 Inheritance[349:303] Age: 5
2013-09-22 21:20:09.846 Inheritance[349:303] Education: MBA
アクセス制御と継承
派生クラスは、インターフェイスクラスで定義されている場合、その基本クラスのすべてのプライベートメンバーにアクセスできますが、実装ファイルで定義されているプライベートメンバーにはアクセスできません。
私たちは、次の方法でそれらにアクセスできる人に応じてさまざまなアクセスタイプを要約することができます-
派生クラスは、次の例外を除き、すべての基本クラスのメソッドと変数を継承します-
- 拡張機能を使用して実装ファイルで宣言された変数にはアクセスできません。
- 拡張機能を使用して実装ファイルで宣言されたメソッドにはアクセスできません。
- 継承されたクラスが基本クラスのメソッドを実装する場合、派生クラスのメソッドが実行されます。
Objective-Cポリモーフィズム
「多態性」という言葉は、多くの形式を持つことを意味します。 通常、ポリモーフィズムは、クラスの階層があり、それらが継承によって関連付けられている場合に発生します。
Objective-Cポリモーフィズムとは、メンバー関数を呼び出すと、その関数を呼び出すオブジェクトのタイプに応じて異なる関数が実行されることを意味します。
例について考えてみましょう。すべての形状の基本的なインターフェースを提供するShapeクラスがあります。 SquareおよびRectangleは、基本クラスShapeから派生します。
OOP機能 polymorphism について示すメソッドprintAreaがあります。
#import <Foundation/Foundation.h>
@interface Shape : NSObject {
CGFloat area;
}
- (void)printArea;
- (void)calculateArea;
@end
@implementation Shape
- (void)printArea {
NSLog(@"The area is %f", area);
}
- (void)calculateArea {
}
@end
@interface Square : Shape {
CGFloat length;
}
- (id)initWithSide:(CGFloat)side;
- (void)calculateArea;
@end
@implementation Square
- (id)initWithSide:(CGFloat)side {
length = side;
return self;
}
- (void)calculateArea {
area = length *length;
}
- (void)printArea {
NSLog(@"The area of square is %f", area);
}
@end
@interface Rectangle : Shape {
CGFloat length;
CGFloat breadth;
}
- (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth;
@end
@implementation Rectangle
- (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth {
length = rLength;
breadth = rBreadth;
return self;
}
- (void)calculateArea {
area = length* breadth;
}
@end
int main(int argc, const char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
Shape *square = [[Square alloc]initWithSide:10.0];
[square calculateArea];
[square printArea];
Shape *rect = [[Rectangle alloc]
initWithLength:10.0 andBreadth:5.0];
[rect calculateArea];
[rect printArea];
[pool drain];
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-22 21:21:50.785 Polymorphism[358:303] The area of square is 100.000000
2013-09-22 21:21:50.786 Polymorphism[358:303] The area is 50.000000
メソッドcomputeAreaおよびprintAreaの可用性に基づく上記の例では、基本クラスまたは派生クラスのメソッドが実行されました。
多態性は、2つのクラスのメソッド実装に基づいて、基本クラスと派生クラス間のメソッドの切り替えを処理します。
Objective-Cデータのカプセル化
すべてのObjective-Cプログラムは、次の2つの基本的な要素で構成されています-
- プログラムステートメント(コード)-これはアクションを実行するプログラムの一部であり、メソッドと呼ばれます。
- プログラムデータ-データは、プログラム機能の影響を受けるプログラムの情報です。
カプセル化は、オブジェクト指向プログラミングの概念であり、データとデータを操作する機能を結び付け、外部の干渉や誤用から安全に保ちます。 データのカプセル化により、*データ隠蔽*という重要なOOPコンセプトが生まれました。
- データのカプセル化*は、データとそれらを使用する機能をバンドルするメカニズムです。*データの抽象化*は、インターフェースのみを公開し、実装の詳細をユーザーから隠すメカニズムです。
Objective-Cは、 classes と呼ばれるユーザー定義型の作成を通じて、カプセル化とデータ隠蔽のプロパティをサポートします。 たとえば-
@interface Adder : NSObject {
NSInteger total;
}
- (id)initWithInitialNumber:(NSInteger)initialNumber;
- (void)addNumber:(NSInteger)newNumber;
- (NSInteger)getTotal;
@end
変数totalはプライベートであり、クラスの外部からアクセスできません。 これは、プログラムの他の部分ではなく、Adderクラスの他のメンバーのみがアクセスできることを意味します。 これは、カプセル化を実現する1つの方法です。
インターフェイスファイル内のメソッドはアクセス可能で、スコープ内でパブリックです。
*extensions* を使用して記述されたプライベートメソッドがあります。これについては、今後の章で学習します。
データのカプセル化の例
パブリックおよびプライベートメンバ変数を使用してクラスを実装するObjective-Cプログラムは、データのカプセル化とデータの抽象化の例です。 次の例を考慮してください-
#import <Foundation/Foundation.h>
@interface Adder : NSObject {
NSInteger total;
}
- (id)initWithInitialNumber:(NSInteger)initialNumber;
- (void)addNumber:(NSInteger)newNumber;
- (NSInteger)getTotal;
@end
@implementation Adder
-(id)initWithInitialNumber:(NSInteger)initialNumber {
total = initialNumber;
return self;
}
- (void)addNumber:(NSInteger)newNumber {
total = total + newNumber;
}
- (NSInteger)getTotal {
return total;
}
@end
int main(int argc, const char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
Adder *adder = [[Adder alloc]initWithInitialNumber:10];
[adder addNumber:5];
[adder addNumber:4];
NSLog(@"The total is %ld",[adder getTotal]);
[pool drain];
return 0;
}
上記のコードをコンパイルして実行すると、次の結果が生成されます-
2013-09-22 21:17:30.485 DataEncapsulation[317:303] The total is 19
上記のクラスは数値を加算し、合計を返します。 パブリックメンバー addNum および getTotal は外部世界へのインターフェイスであり、ユーザーはクラスを使用するためにそれらを知る必要があります。 プライベートメンバー total は、外部からは隠されていますが、クラスが適切に動作するために必要です。
戦略の設計
私たちのほとんどは、実際にクラスメンバーを公開する必要がない限り、デフォルトではクラスメンバーをプライベートにするという苦い経験を通じて学んでいます。 それはちょうど良い*カプセル化*です。
データのカプセル化は、Objective-Cを含むすべてのオブジェクト指向プログラミング(OOP)言語のコア機能の1つであるため、データのカプセル化を理解することが重要です。
Objective-Cのカテゴリ
特定の状況でのみ役立つ動作を追加することで、既存のクラスを拡張したい場合があります。 そのような拡張機能を既存のクラスに追加するために、Objective-Cは categoories と extensions を提供します。
既存のクラスにメソッドを追加する必要がある場合、たとえば、独自のアプリケーションで何かを簡単に実行できるようにする機能を追加する必要がある場合、最も簡単な方法はカテゴリを使用することです。
カテゴリを宣言する構文は、標準のObjective-Cクラスの説明と同様に@interfaceキーワードを使用しますが、サブクラスからの継承を示すものではありません。 代わりに、このように、括弧内のカテゴリの名前を指定します-
@interface ClassName (CategoryName)
@end
カテゴリーの特徴
- 元の実装ソースコードを持っていない場合でも、カテゴリは任意のクラスに対して宣言できます。
- カテゴリで宣言したメソッドは、元のクラスのすべてのインスタンスと、元のクラスのサブクラスで使用できます。 *実行時に、カテゴリによって追加されたメソッドと元のクラスによって実装されたメソッドに違いはありません。
次に、サンプルのカテゴリ実装を見てみましょう。 CocoaクラスNSStringにカテゴリを追加しましょう。 このカテゴリにより、新しいメソッドgetCopyRightStringを追加して、著作権文字列を返すことができます。 以下に示します。
#import <Foundation/Foundation.h>
@interface NSString(MyAdditions)
+(NSString* )getCopyRightString;
@end
@implementation NSString(MyAdditions)
+(NSString *)getCopyRightString {
return @"Copyright finddevguides.com 2013";
}
@end
int main(int argc, const char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString *copyrightString = [NSString getCopyRightString];
NSLog(@"Accessing Category: %@",copyrightString);
[pool drain];
return 0;
}
プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-22 21:19:12.125 Categories[340:303] Accessing Category: Copyright finddevguides.com 2013
カテゴリによって追加されたメソッドは、クラスとそのサブクラスのすべてのインスタンスで使用できますが、追加メソッドを使用するソースコードファイルにカテゴリヘッダーファイルをインポートする必要があります。インポートしない場合、実行されますコンパイラの警告とエラー。
この例では、クラスが1つしかないため、ヘッダーファイルを含めていません。そのような場合は、上記のようにヘッダーファイルを含める必要があります。
Objective-Cのポーズ
Objective-Cで Posing を開始する前に、Mac OS X 10.5で廃止が宣言されており、その後使用できないことをお知らせします。 したがって、これらの非推奨のメソッドを気にしない人はこの章を飛ばすことができます。
Objective-Cでは、クラスがプログラム内の別のクラスを完全に置き換えることができます。 置き換えクラスは、ターゲットクラスを「装う」と言われます。 ポーズをサポートしたバージョンの場合、ターゲットクラスに送信されたすべてのメッセージは、代わりにポーズクラスによって受信されます。
NSObjectには、上記のように既存のクラスを置き換えることができるposeAsClass −メソッドが含まれています。
ポーズの制限
- クラスは、直接または間接のスーパークラスの1つとしてのみポーズをとることができます。
- ポーズクラスは、ターゲットクラスにない新しいインスタンス変数を定義してはなりません(ただし、メソッドを定義またはオーバーライドできます)。
- ターゲットクラスは、ポーズの前にメッセージを受信していない可能性があります。
- ポーズをとるクラスは、superを介してオーバーライドされたメソッドを呼び出すことができるため、ターゲットクラスの実装を組み込むことができます。 *ポーズクラスは、カテゴリで定義されたメソッドをオーバーライドできます。
#import <Foundation/Foundation.h>
@interface MyString : NSString
@end
@implementation MyString
- (NSString* )stringByReplacingOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement {
NSLog(@"The Target string is %@",target);
NSLog(@"The Replacement string is %@",replacement);
}
@end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[MyString poseAsClass:[NSString class]];
NSString* string = @"Test";
[string stringByReplacingOccurrencesOfString:@"a" withString:@"c"];
[pool drain];
return 0;
}
古いMac OS X(V_10.5以前)でプログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-22 21:23:46.829 Posing[372:303] The Target string is a
2013-09-22 21:23:46.830 Posing[372:303] The Replacement string is c
上記の例では、元のメソッドを実装で汚染しただけで、上記のメソッドを使用したすべてのNSString操作で影響を受けます。
Objective-C拡張
クラス拡張はカテゴリとある程度類似していますが、コンパイル時にソースコードを持っているクラスにのみ追加できます(クラスはクラス拡張と同時にコンパイルされます)。
クラス拡張によって宣言されたメソッドは、元のクラスの実装ブロックに実装されているため、たとえば、NSStringのようなCocoaまたはCocoa Touchクラスなどのフレームワーククラスでクラス拡張を宣言することはできません。
拡張機能は、実際にはカテゴリ名のないカテゴリです。 しばしば*匿名カテゴリ*と呼ばれます。
拡張を宣言する構文は、標準のObjective-Cクラスの説明と同様に@interfaceキーワードを使用しますが、サブクラスからの継承を示すものではありません。 代わりに、以下に示すように、括弧を追加するだけです-
@interface ClassName ()
@end
拡張機能の特性
- ソースコードの元の実装があるクラスに対してのみ、拡張機能をクラスに対して宣言することはできません。
- 拡張機能は、クラスに固有のプライベートメソッドとプライベート変数を追加します。 *拡張内で宣言されたメソッドまたは変数は、継承されたクラスからもアクセスできません。
拡張機能の例
拡張機能を持つクラスSampleClassを作成しましょう。 拡張機能では、プライベート変数internalIDを用意します。
次に、internalIDの処理後にexternalIDを返すメソッドgetExternalIDを用意します。
以下に例を示しますが、これはオンラインコンパイラでは機能しません。
#import <Foundation/Foundation.h>
@interface SampleClass : NSObject {
NSString* name;
}
- (void)setInternalID;
- (NSString *)getExternalID;
@end
@interface SampleClass() {
NSString *internalID;
}
@end
@implementation SampleClass
- (void)setInternalID {
internalID = [NSString stringWithFormat:
@"UNIQUEINTERNALKEY%dUNIQUEINTERNALKEY",arc4random()%100];
}
- (NSString *)getExternalID {
return [internalID stringByReplacingOccurrencesOfString:
@"UNIQUEINTERNALKEY" withString:@""];
}
@end
int main(int argc, const char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass setInternalID];
NSLog(@"ExternalID: %@",[sampleClass getExternalID]);
[pool drain];
return 0;
}
プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-22 21:18:31.754 Extensions[331:303] ExternalID: 51
上記の例では、internalIDが直接返されないことがわかります。 ここでは、UNIQUEINTERNALKEYを削除し、メソッドgetExternalIDで残りの値のみを使用できるようにします。
上記の例では文字列操作を使用していますが、暗号化/復号化などの多くの機能を使用できます。
Objective-Cプロトコル
Objective-Cでは、特定の状況で使用されると予想されるメソッドを宣言するプロトコルを定義できます。 プロトコルは、プロトコルに準拠するクラスに実装されます。
簡単な例は、ネットワークURL処理クラスです。ネットワークURLフェッチ操作が終了すると、呼び出しクラスを推定するprocessCompletedデリゲートメソッドなどのメソッドを持つプロトコルがあります。
プロトコルの構文を以下に示します。
@protocol ProtocolName
@required
//list of required methods
@optional
//list of optional methods
@end
キーワード @ required のメソッドは、プロトコルに準拠するクラスに実装する必要があり、 @ optional キーワードのメソッドは実装がオプションです。
プロトコルに準拠するクラスの構文は次のとおりです。
@interface MyClass : NSObject <MyProtocol>
...
@end
つまり、MyClassのインスタンスは、インターフェイスで特に宣言されたメソッドに応答するだけでなく、MyProtocolで必要なメソッドの実装も提供します。 クラスインターフェイスでプロトコルメソッドを再宣言する必要はありません-プロトコルの採用で十分です。
複数のプロトコルを採用するクラスが必要な場合は、それらをコンマ区切りリストとして指定できます。 プロトコルを実装する呼び出し元オブジェクトの参照を保持するデリゲートオブジェクトがあります。
例を以下に示します。
#import <Foundation/Foundation.h>
@protocol PrintProtocolDelegate
- (void)processCompleted;
@end
@interface PrintClass :NSObject {
id delegate;
}
- (void) printDetails;
- (void) setDelegate:(id)newDelegate;
@end
@implementation PrintClass
- (void)printDetails {
NSLog(@"Printing Details");
[delegate processCompleted];
}
- (void) setDelegate:(id)newDelegate {
delegate = newDelegate;
}
@end
@interface SampleClass:NSObject<PrintProtocolDelegate>
- (void)startAction;
@end
@implementation SampleClass
- (void)startAction {
PrintClass *printClass = [[PrintClass alloc]init];
[printClass setDelegate:self];
[printClass printDetails];
}
-(void)processCompleted {
NSLog(@"Printing Process Completed");
}
@end
int main(int argc, const char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass startAction];
[pool drain];
return 0;
}
プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-22 21:15:50.362 Protocols[275:303] Printing Details
2013-09-22 21:15:50.364 Protocols[275:303] Printing Process Completed
上記の例では、delgateメソッドがどのように呼び出され実行されるかを見てきました。 startActionで始まり、プロセスが完了すると、デリゲートメソッドprocessCompletedが呼び出され、操作が完了します。
iOSまたはMacアプリでは、デリゲートなしでプログラムを実装することはありません。 そのため、デリゲートの使用方法を理解することが重要です。 デリゲートオブジェクトは、メモリリークを避けるためにunsafe_unretainedプロパティタイプを使用する必要があります。
Objective-C動的バインディング
動的バインディングは、コンパイル時ではなく実行時に呼び出すメソッドを決定します。 動的バインディングは、遅延バインディングとも呼ばれます。 Objective-Cでは、すべてのメソッドは実行時に動的に解決されます。 実行される正確なコードは、メソッド名(セレクター)と受信オブジェクトの両方によって決定されます。
動的バインディングにより、ポリモーフィズムが可能になります。 たとえば、RectangleやSquareを含むオブジェクトのコレクションを考えます。 各オブジェクトには、printAreaメソッドの独自の実装があります。
次のコードフラグメントでは、式[anObject printArea]によって実行される実際のコードは実行時に決定されます。 ランタイムシステムは、実行されたメソッドのセレクターを使用して、anObjectのどのクラスでも適切なメソッドを識別します。
動的バインディングを説明する簡単なコードを見てみましょう。
#import <Foundation/Foundation.h>
@interface Square:NSObject {
float area;
}
- (void)calculateAreaOfSide:(CGFloat)side;
- (void)printArea;
@end
@implementation Square
- (void)calculateAreaOfSide:(CGFloat)side {
area = side *side;
}
- (void)printArea {
NSLog(@"The area of square is %f",area);
}
@end
@interface Rectangle:NSObject {
float area;
}
- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth;
- (void)printArea;
@end
@implementation Rectangle
- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth {
area = length* breadth;
}
- (void)printArea {
NSLog(@"The area of Rectangle is %f",area);
}
@end
int main() {
Square *square = [[Square alloc]init];
[square calculateAreaOfSide:10.0];
Rectangle *rectangle = [[Rectangle alloc]init];
[rectangle calculateAreaOfLength:10.0 andBreadth:5.0];
NSArray *shapes = [[NSArray alloc]initWithObjects: square, rectangle,nil];
id object1 = [shapes objectAtIndex:0];
[object1 printArea];
id object2 = [shapes objectAtIndex:1];
[object2 printArea];
return 0;
}
プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-28 07:42:29.821 demo[4916] The area of square is 100.000000
2013-09-28 07:42:29.821 demo[4916] The area of Rectangle is 50.000000
上記の例でわかるように、printAreaメソッドは実行時に動的に選択されます。 これは動的バインディングの例であり、同様の種類のオブジェクトを扱う多くの状況で非常に役立ちます。
Objective-C複合オブジェクト
オブジェクトを埋め込むクラスを定義するクラスクラスター内にサブクラスを作成できます。 これらのクラスオブジェクトは複合オブジェクトです。 そのため、クラスクラスターとは何かを疑問に思うかもしれません。 そのため、最初にクラスクラスターとは何かを確認します。
クラスクラスター
クラスクラスターは、基盤フレームワークが広範囲に使用する設計パターンです。 クラスクラスターは、パブリック抽象スーパークラスの下にプライベートコンクリートサブクラスの数をグループ化します。 このようにクラスをグループ化することで、オブジェクト指向フレームワークの一般に公開されているアーキテクチャを、その機能性を損なうことなく単純化することができます。 クラスクラスターは、 abstract factory デザインパターンに基づいています。
簡単にするために、同様の機能のために複数のクラスを作成する代わりに、入力の値に基づいてその処理を処理する単一のクラスを作成します。
たとえば、NSNumberには、char、int、boolなどのクラスのクラスターが多数あります。 それらすべてを単一のクラスにグループ化し、単一のクラスで同様の操作を処理します。 NSNumberは、これらのプリミティブ型の値を実際にオブジェクトにラップします。
複合オブジェクトとは何ですか?
プライベートクラスタオブジェクトを独自のデザインのオブジェクトに埋め込むことにより、複合オブジェクトを作成します。 この複合オブジェクトは、その基本機能をクラスターオブジェクトに依存し、複合オブジェクトが特定の方法で処理したいメッセージのみをインターセプトします。 このアーキテクチャにより、記述する必要のあるコードの量が減り、Foundation Frameworkが提供するテスト済みコードを活用できます。
これを次の図で説明します。
複合オブジェクトは、自身をクラスターの抽象スーパークラスのサブクラスとして宣言する必要があります。 サブクラスとして、スーパークラスのプリミティブメソッドをオーバーライドする必要があります。 派生メソッドをオーバーライドすることもできますが、派生メソッドはプリミティブメソッドを介して機能するため、これは必要ありません。
NSArrayクラスのcountメソッドは一例です。それがオーバーライドするメソッドの介在オブジェクトの実装は、次のように簡単にすることができます-
- (unsigned)count {
return [embeddedObject count];
}
上記の例では、埋め込みオブジェクトは実際にはNSArray型です。
複合オブジェクトの例
次に、完全な例を見るために、以下に示すAppleのドキュメントの例を見てみましょう。
#import <Foundation/Foundation.h>
@interface ValidatingArray : NSMutableArray {
NSMutableArray *embeddedArray;
}
+ validatingArray;
- init;
- (unsigned)count;
- objectAtIndex:(unsigned)index;
- (void)addObject:object;
- (void)replaceObjectAtIndex:(unsigned)index withObject:object;
- (void)removeLastObject;
- (void)insertObject:object atIndex:(unsigned)index;
- (void)removeObjectAtIndex:(unsigned)index;
@end
@implementation ValidatingArray
- init {
self = [super init];
if (self) {
embeddedArray = [[NSMutableArray allocWithZone:[self zone]] init];
}
return self;
}
+ validatingArray {
return [[self alloc] init] ;
}
- (unsigned)count {
return [embeddedArray count];
}
- objectAtIndex:(unsigned)index {
return [embeddedArray objectAtIndex:index];
}
- (void)addObject:(id)object {
if (object != nil) {
[embeddedArray addObject:object];
}
}
- (void)replaceObjectAtIndex:(unsigned)index withObject:(id)object; {
if (index <[embeddedArray count] && object != nil) {
[embeddedArray replaceObjectAtIndex:index withObject:object];
}
}
- (void)removeLastObject; {
if ([embeddedArray count] > 0) {
[embeddedArray removeLastObject];
}
}
- (void)insertObject:(id)object atIndex:(unsigned)index; {
if (object != nil) {
[embeddedArray insertObject:object atIndex:index];
}
}
- (void)removeObjectAtIndex:(unsigned)index; {
if (index <[embeddedArray count]) {
[embeddedArray removeObjectAtIndex:index];
}
}
@end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
ValidatingArray* validatingArray = [ValidatingArray validatingArray];
[validatingArray addObject:@"Object1"];
[validatingArray addObject:@"Object2"];
[validatingArray addObject:[NSNull null]];
[validatingArray removeObjectAtIndex:2];
NSString *aString = [validatingArray objectAtIndex:1];
NSLog(@"The value at Index 1 is %@",aString);
[pool drain];
return 0;
}
プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-28 22:03:54.294 demo[6247] The value at Index 1 is Object2
上記の例では、配列の1つの関数を検証しても、通常のシナリオではクラッシュにつながるnullオブジェクトを追加できないことがわかります。 しかし、検証配列がそれを処理します。 同様に、検証配列の各メソッドは、通常の操作シーケンスとは別に検証プロセスを追加します。
Obj-C Foundationフレームワーク
Appleのドキュメントを参照すると、以下に示すFoundationフレームワークの詳細を確認できます。
Foundationフレームワークは、Objective-Cクラスの基本層を定義します。 有用なプリミティブオブジェクトクラスのセットを提供することに加えて、Objective-C言語でカバーされない機能を定義するいくつかのパラダイムを導入します。 財団のフレームワークは、これらの目標を念頭に置いて設計されています-
- 基本的なユーティリティクラスの小さなセットを提供します。
- 割り振り解除などの一貫した規則を導入することにより、ソフトウェア開発を容易にします。
- Unicode文字列、オブジェクトの永続性、およびオブジェクトの配布をサポートします。
- OSの独立性を提供して、移植性を高めます。
このフレームワークは、Appleに買収されたNeXTStepによって開発され、これらの基礎クラスはMac OS XおよびiOSの一部になりました。 NeXTStepによって開発されたため、クラスプレフィックスは「NS」です。
すべてのサンプルプログラムでFoundation Frameworkを使用しました。 Foundation Frameworkを使用することはほぼ必須です。
一般的に、Objective-Cクラスをインポートするには*#import <Foundation/NSString.h> のようなものを使用しますが、インポートするクラスが多すぎることを避けるため、すべて#import <Foundation/Foundation.h&gt *にインポートします。
NSObjectは、Foundation Kitクラスを含むすべてのオブジェクトの基本クラスです。 メモリ管理の方法を提供します。 また、ランタイムシステムへの基本的なインターフェイスと、Objective-Cオブジェクトとして動作する機能も提供します。 基本クラスはなく、すべてのクラスのルートです。
機能に基づく基礎クラス
| Sr.No. | Loop Type & Description |
|---|---|
| 1 |
NSArray、NSDictionary、およびNSSetは、あらゆるクラスのObjective-Cオブジェクトのストレージを提供します。 |
| 2 |
NSCharacterSetは、NSStringおよびNSScannerクラスで使用される文字のさまざまなグループを表します。 NSStringクラスはテキスト文字列を表し、文字列を検索、結合、および比較するためのメソッドを提供します。 NSScannerオブジェクトは、NSStringオブジェクトから数字と単語をスキャンするために使用されます。 |
| 3 |
NSDate、NSTimeZone、およびNSCalendarクラスは時刻と日付を格納し、暦情報を表します。 日付と時刻の差を計算する方法を提供します。 NSLocaleとともに、日付と時刻をさまざまな形式で表示し、世界の場所に基づいて時刻と日付を調整するためのメソッドを提供します。 |
| 4 |
例外処理は、予期しない状況を処理するために使用され、NSExceptionを備えたObjective-Cで提供されます。 |
| 5 |
ファイル処理は、NSFileManagerクラスの助けを借りて行われます。 |
| 6 |
一般的なインターネットプロトコルへのアクセスを提供するクラスとプロトコルのセット。 |
Objective-C高速列挙
高速列挙は、コレクション全体の列挙に役立つObjective-Cの機能です。 したがって、高速列挙について知るためには、まずコレクションについて知る必要があります。これについては、次のセクションで説明します。
Objective-Cのコレクション
コレクションは基本的な構成要素です。 他のオブジェクトを保持および管理するために使用されます。 コレクションの全体的な目的は、オブジェクトを効率的に保存および取得する一般的な方法を提供することです。
コレクションにはいくつかの異なるタイプがあります。 それらはすべて、他のオブジェクトを保持できるという同じ目的を果たしますが、オブジェクトの取得方法が主に異なります。 Objective-Cで使用される最も一般的なコレクションは次のとおりです-
- NSSet
- NSArray
- NSDictionary
- NSMutableSet
- NSMutableArray *NSMutableDictionary
これらの構造の詳細については、link:/objective_c/objective_c_foundation_framework [Foundation Framework]のデータストレージを参照してください。
高速列挙構文
for (classType variable in collectionObject ) {
statements
}
高速列挙の例を次に示します。
#import <Foundation/Foundation.h>
int main() {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSArray *array = [[NSArray alloc]
initWithObjects:@"string1", @"string2",@"string3",nil];
for(NSString *aString in array) {
NSLog(@"Value: %@",aString);
}
[pool drain];
return 0;
}
プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-28 06:26:22.835 demo[7426] Value: string1
2013-09-28 06:26:22.836 demo[7426] Value: string2
2013-09-28 06:26:22.836 demo[7426] Value: string3
出力からわかるように、配列内の各オブジェクトは順番に出力されます。
後方列挙
for (classType variable in [collectionObject reverseObjectEnumerator] ) {
statements
}
高速列挙のreverseObjectEnumeratorの例を次に示します。
#import <Foundation/Foundation.h>
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray* array = [[NSArray alloc]
initWithObjects:@"string1", @"string2",@"string3",nil];
for(NSString *aString in [array reverseObjectEnumerator]) {
NSLog(@"Value: %@",aString);
}
[pool drain];
return 0;
}
プログラムをコンパイルして実行すると、次の結果が得られます。
2013-09-28 06:27:51.025 demo[12742] Value: string3
2013-09-28 06:27:51.025 demo[12742] Value: string2
2013-09-28 06:27:51.025 demo[12742] Value: string1
出力からわかるように、配列内の各オブジェクトは、通常の高速列挙と比較して逆の順序で印刷されます。
Obj-Cメモリ管理
メモリ管理は、プログラミング言語で最も重要なプロセスの1つです。 オブジェクトのメモリが必要なときに割り当てられ、不要になったときに割り当てを解除するプロセスです。
オブジェクトメモリの管理はパフォーマンスの問題です。アプリケーションが不要なオブジェクトを解放しないと、メモリフットプリントが増大し、パフォーマンスが低下します。
Objective-Cのメモリ管理手法は、大きく2つのタイプに分類できます。
- 「手動保持リリース」またはMRR
- 「自動参照カウント」またはARC
「手動保持リリース」またはMRR
MRRでは、オブジェクトを独自に追跡することでメモリを明示的に管理します。 これは、FoundationクラスNSObjectがランタイム環境とともに提供する参照カウントと呼ばれるモデルを使用して実装されます。
MRRとARCの唯一の違いは、前者では保持と解放が手動で処理され、後者では自動的に処理されることです。
次の図は、Objective-Cでのメモリ管理の動作例を示しています。
クラスAオブジェクトのメモリライフサイクルを上の図に示します。 ご覧のとおり、保持カウントはオブジェクトの下に表示されます。オブジェクトの保持カウントが0になると、オブジェクトは完全に解放され、メモリは他のオブジェクトが使用できるように割り当て解除されます。
クラスAオブジェクトは、NSObjectで利用可能なalloc/initメソッドを使用して最初に作成されます。 現在、保持カウントは1になります。
現在、クラスBはクラスAのオブジェクトを保持し、クラスAのオブジェクトの保持カウントは2になります。
次に、クラスCはオブジェクトのコピーを作成します。 これで、インスタンス変数に同じ値を持つクラスAの別のインスタンスとして作成されます。 ここでは、保持カウントは1であり、元のオブジェクトの保持カウントではありません。 これは、図の点線で表されています。
コピーされたオブジェクトは、リリースメソッドを使用してクラスCによってリリースされ、保持カウントが0になるため、オブジェクトは破棄されます。
最初のクラスAオブジェクトの場合、保持カウントは2であり、破棄するために2回解放する必要があります。 これは、保持カウントをそれぞれ1と0に減らすクラスAとクラスBのリリースステートメントによって行われます。 最後に、オブジェクトは破棄されます。
MRR基本ルール
- 作成するオブジェクトはすべて所有します。名前が「alloc」、「new」、「copy」、または「mutableCopy」で始まるメソッドを使用してオブジェクトを作成します
- retainを使用してオブジェクトの所有権を取得できます。受信したオブジェクトは通常、受信したメソッド内で有効なままであることが保証され、そのメソッドはオブジェクトを呼び出し側に安全に返すこともできます。 私たちは2つの状況で保持を使用します-
- アクセサメソッドまたはinitメソッドの実装では、オブジェクトの所有権を取得するために、プロパティ値として保存する必要があります。
- オブジェクトが他の操作の副作用として無効化されるのを防ぐため。
- 不要になったら、所有するオブジェクトの所有権を放棄する必要があります。オブジェクトにリリースメッセージまたは自動リリースメッセージを送信して、オブジェクトの所有権を放棄します。 したがって、Cocoaの用語では、オブジェクトの所有権を放棄することは、通常、オブジェクトを「解放する」と呼ばれます。
- 所有していないオブジェクトの所有権を放棄してはなりません。これは、明示的に述べられた以前のポリシールールの当然の結果です。
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
[super dealloc];
}
@end
int main() {
/*my first program in Objective-C*/
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
NSLog(@"Retain Count after initial allocation: %d",
[sampleClass retainCount]);
[sampleClass retain];
NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"SampleClass dealloc will be called before this");
//Should set the object to nil
sampleClass = nil;
return 0;
}
上記のプログラムをコンパイルすると、次の出力が得られます。
2013-09-28 04:39:52.310 demo[8385] Hello, World!
2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1
2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2
2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1
2013-09-28 04:39:52.311 demo[8385] Object deallocated
2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this
「自動参照カウント」またはARC
自動参照カウントまたはARCでは、システムはMRRと同じ参照カウントシステムを使用しますが、コンパイル時に適切なメモリ管理メソッド呼び出しを挿入します。 新しいプロジェクトにはARCを使用することを強くお勧めします。 ARCを使用する場合、状況によっては役立つことがありますが、通常、このドキュメントで説明されている基本的な実装を理解する必要はありません。 ARCの詳細については、https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introductionl [ARCへの移行に関するリリースノート]を参照してください。
前述したように、ARCでは、リリースメソッドを保持する必要はありません。コンパイラによって処理されるためです。 実際、Objective-Cの基本的なプロセスは同じです。 内部的に保持および解放操作を使用するため、開発者はこれらの操作を気にせずにコーディングしやすくなります。これにより、書き込まれるコードの量とメモリリークの可能性の両方が削減されます。
Mac OS-XでMRRとともに使用されるガベージコレクションと呼ばれる別の原則がありましたが、OS-X Mountain Lionでの非推奨以来、MRRとともに議論されていません。 また、iOSオブジェクトにはガベージコレクション機能がありませんでした。 また、ARCでは、OS-Xでもガベージコレクションは使用されません。
簡単なARCの例を次に示します。 これは、ARCをサポートしていないため、オンラインコンパイラでは機能しません。
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
}
@end
int main() {
/*my first program in Objective-C*/
@autoreleasepool {
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
sampleClass = nil;
}
return 0;
}
上記のプログラムをコンパイルすると、次の出力が得られます。
2013-09-28 04:45:47.310 demo[8385] Hello, World!
2013-09-28 04:45:47.311 demo[8385] Object deallocated