Objective-Cクイックガイド

Objective-Cは、Small Talkプログラミング言語の機能を追加してオブジェクト指向言語にすることにより、Cプログラミング言語の上に開発された汎用言語です。これは主に、iOSおよびMac OSXオペレーティングシステムとそのアプリケーションの開発に使用されます。

当初、Objective-CはNeXTによってNeXTSTEP OS用に開発され、そこからAppleによってiOSおよびMac OSX用に引き継がれました。

オブジェクト指向プログラミング

オブジェクト指向開発の4つの柱を含むオブジェクト指向プログラミングを完全にサポートします-

  • Encapsulation
  • データの隠蔽
  • Inheritance
  • Polymorphism

サンプルコード

#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

Foundation Frameworkは多数の機能セットを提供し、それらを以下にリストします。

  • NSArray、NSDictionary、NSSetなどの拡張データ型のリストが含まれています。

  • これは、ファイルや文字列などを操作する豊富な関数セットで構成されています。

  • URL処理、日付フォーマット、データ処理、エラー処理などのユーティリティの機能を提供します。

学習Objective-C

Objective-Cを学ぶときに行うべき最も重要なことは、概念に焦点を合わせ、言語の技術的な詳細に迷わないことです。

プログラミング言語を学ぶ目的は、より優れたプログラマーになることです。つまり、新しいシステムの設計と実装、および古いシステムの保守をより効果的に行うことです。

Objective-Cの使用

前述のように、Objective-CはiOSおよびMac OS Xで使用されます。iOSユーザーの基盤が大きく、Mac OSXユーザーが大幅に増加しています。そして、Appleは品質を第一に重視しているので、Objective-Cを学び始めた人にとっては素晴らしいものです。

ローカル環境のセットアップ

それでもObjective-Cプログラミング言語用に環境をセットアップする場合は、コンピューターで使用できる次の2つのソフトウェア((a)テキストエディターと(b)GCCコンパイラー)が必要です。

テキストエディタ

これは、プログラムの入力に使用されます。いくつかのエディターの例には、Windowsメモ帳、OS Editコマンド、Brief、Epsilon、EMACS、vimまたはviが含まれます。

テキストエディタの名前とバージョンは、オペレーティングシステムによって異なる場合があります。たとえば、メモ帳はWindowsで使用され、vimまたはviはWindowsだけでなくLinuxまたはUNIXでも使用できます。

エディタで作成するファイルはソースファイルと呼ばれ、プログラムのソースコードが含まれています。Objective-Cプログラムのソースファイルには、通常、拡張子「」が付けられています。.m"。

プログラミングを開始する前に、テキストエディタが1つあり、コンピュータプログラムを作成し、ファイルに保存し、コンパイルして、最後に実行するのに十分な経験があることを確認してください。

GCCコンパイラ

ソースファイルに記述されたソースコードは、プログラムの人間が読める形式のソースです。CPUが実際に与えられた指示に従ってプログラムを実行できるように、機械語に変換するために「コンパイル」する必要があります。

このGCCコンパイラは、ソースコードを最終的な実行可能プログラムにコンパイルするために使用されます。あなたはプログラミング言語コンパイラについての基本的な知識を持っていると思います。

GCCコンパイラはさまざまなプラットフォームで無料で利用できます。さまざまなプラットフォームでセットアップする手順を以下に説明します。

UNIX / Linuxへのインストール

最初のステップは、gccObjective-Cパッケージと一緒にgccをインストールすることです。これは-によって行われます

$ 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://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.mObjective-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 tutorialsPoint[12906] hello world

MacOSへのインストール

Mac OS Xを使用している場合、GCCを入手する最も簡単な方法は、AppleのWebサイトからXcode開発環境をダウンロードし、簡単なインストール手順に従うことです。Xcodeを設定すると、C / C ++用のGNUコンパイラを使用できるようになります。

Xcodeは現在developer.apple.com/technologies/tools/で入手できます。

Windowsへのインストール

WindowsでObjective-Cプログラムを実行するには、MinGWとGNUStepCoreをインストールする必要があります。どちらもで入手可能ですhttps://www.gnu.org/software/gnustep/windows/installer.html。

まず、MSYS / MinGWシステムパッケージをインストールする必要があります。次に、GNUstepCoreパッケージをインストールする必要があります。どちらも、自明の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 tutorialsPoint[1200] hello world

Objective-Cプログラミング言語の基本的な構成要素を学習する前に、次の章で参照できるように、最低限のObjective-Cプログラム構造を見てみましょう。

Objective-C HelloWorldの例

Objective-Cプログラムは、基本的に次の部分で構成されています。

  • プリプロセッサコマンド
  • Interface
  • Implementation
  • Method
  • Variables
  • ステートメントと式
  • Comments

「HelloWorld」という単語を出力する簡単なコードを見てみましょう-

#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ファイルをインクルードするように指示します。

  • 次の行@interfaceSampleClass:NSObjectは、インターフェースの作成方法を示しています。すべてのオブジェクトの基本クラスであるNSObjectを継承します。

  • 次の行-(void)sampleMethod; メソッドを宣言する方法を示します。

  • 次の行@endは、インターフェースの終わりを示します。

  • 次の行@implementationSampleClassは、インターフェースSampleClassを実装する方法を示しています。

  • 次の行-(void)sampleMethod {}は、sampleMethodの実装を示しています。

  • 次の行@endは、実装の終了を示します。

  • 次の行intmain()は、プログラムの実行を開始するmain関数です。

  • 次の行/ * ... * /はコンパイラーによって無視され、プログラムにコメントを追加するために配置されています。したがって、このような行はプログラムではコメントと呼ばれます。

  • 次の行NSLog(...)は、Objective-Cで使用できる別の関数であり、「Hello、World!」というメッセージが表示されます。画面に表示されます。

  • 次の行 return 0; main()関数を終了し、値0を返します。

Objective-Cプログラムのコンパイルと実行

プログラムをコンパイルして実行すると、次の結果が得られます。

2017-10-06 07:48:32.020 demo[65832] Hello, World!

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はcase-sensitiveプログラミング言語。したがって、Manpowermanpowerは、Objective-Cの2つの異なる識別子です。受け入れ可能な識別子の例を次に示します-

mohd       zara    abc   move_name  a_123
myname50   _temp   j     a23b9      retVal

キーワード

次のリストは、Objective-Cで予約されている単語のいくつかを示しています。これらの予約語は、定数や変数、またはその他の識別子名として使用することはできません。

自動 そうしないと 長いです スイッチ
ブレーク 列挙型 登録 typedef
場合 extern 戻る 連合
char 浮く ショート 署名なし
const にとって 署名 ボイド
継続する 後藤 のサイズ 揮発性
デフォルト もし 静的 一方
行う int 構造体 _Packed
ダブル プロトコル インターフェース 実装
NSObject NSInteger NSNumber CGFloat
プロパティ 非原子; 保持 強い
弱い unsafe_unretained; 読み書き 読み取り専用

Objective-Cの空白

おそらくコメント付きの空白のみを含む行は空白行と呼ばれ、Objective-Cコンパイラはそれを完全に無視します。

空白は、Objective-Cで空白、タブ、改行文字、およびコメントを説明するために使用される用語です。空白は、ステートメントの一部を別の部分から分離し、コンパイラーが、intなどのステートメント内の1つの要素が終了し、次の要素が開始する場所を識別できるようにします。したがって、次のステートメントでは-

int age;

コンパイラがそれらを区別できるようにするには、intとageの間に少なくとも1つの空白文字(通常はスペース)が必要です。一方、次のステートメントでは、

fruit = apples + oranges;   // get the total fruit

フルーツと=の間、または=とリンゴの間には空白文字は必要ありませんが、読みやすくするために空白文字を自由に含めることができます。

Objective-Cプログラミング言語では、データ型は、さまざまな型の変数または関数を宣言するために使用される広範なシステムを指します。変数のタイプによって、ストレージ内で占有するスペースの量と、格納されているビットパターンがどのように解釈されるかが決まります。

Objective-Cのタイプは次のように分類できます-

シニア番号 タイプと説明
1

Basic Types −

これらは算術型であり、(a)整数型と(b)浮動小数点型の2つの型で構成されます。

2

Enumerated types −

これらも算術型であり、プログラム全体で特定の離散整数値のみを割り当てることができる変数を定義するために使用されます。

3

The type void −

型指定子voidは、使用可能な値がないことを示します。

4

Derived types −

それらには、(a)ポインター型、(b)配列型、(c)構造体型、(d)共用体型、および(e)関数型が含まれます。

配列タイプと構造タイプは、まとめて集約タイプと呼ばれます。関数の型は、関数の戻り値の型を指定します。次のセクションで基本的なタイプを確認しますが、他のタイプについては次の章で説明します。

整数型

次の表に、標準の整数型とそのストレージサイズおよび値の範囲の詳細を示します。

タイプ ストレージサイズ 値の範囲
char 1バイト -128〜127または0〜255
unsigned char 1バイト 0から255
符号付き文字 1バイト -128〜127
int 2または4バイト -32,768〜32,767または-2,147,483,648〜2,147,483,647
unsigned int 2または4バイト 0〜65,535または0〜4,294,967,295
ショート 2バイト -32,768〜32,767
unsigned short 2バイト 0〜65,535
長いです 4バイト -2,147,483,648から2,147,483,647
unsigned long 4バイト 0から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

浮動小数点型

次の表は、ストレージサイズと値の範囲、およびそれらの精度を備えた標準の浮動小数点型の詳細を示しています。

タイプ ストレージサイズ 値の範囲 精度
浮く 4バイト 1.2E-38から3.4E + 38 小数点以下6桁
ダブル 8バイト 2.3E-308から1.7E + 308 小数点以下15桁
ロングダブル 10バイト 3.4E-4932から1.1E + 4932 小数点以下19桁

ヘッダーファイルfloat.hは、これらの値や、プログラムでの実数の2進表現に関するその他の詳細を使用できるようにするマクロを定義します。次の例では、floatタイプが使用するストレージスペースとその範囲値を出力します-

#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種類の状況で使用されます-

シニア番号 タイプと説明
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では大文字と小文字が区別されるため、大文字と小文字は区別されます。前の章で説明した基本的なタイプに基づいて、次の基本的な変数タイプがあります-

シニア番号 タイプと説明
1

char

通常、1オクテット(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プログラムで変数を複数回宣言することはできますが、ファイル、関数、またはコードブロックで定義できるのは1回だけです。

次の例を試してください。変数は上部で宣言されていますが、main関数内で定義および初期化されています-

#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−メモリ位置を参照する式は「左辺値」式と呼ばれます。左辺値は、割り当ての左側または右側のいずれかとして表示される場合があります。

  • rvalue−右辺値という用語は、メモリ内のあるアドレスに格納されているデータ値を指します。右辺値は、値を割り当てることができない式です。つまり、右辺値は割り当ての右側には表示されますが、左側には表示されません。

変数は左辺値であるため、割り当ての左側に表示される場合があります。数値リテラルは右辺値であるため、割り当てられない場合があり、左側に表示することはできません。以下は有効なステートメントです-

int g = 20;

しかし、以下は有効なステートメントではなく、コンパイル時エラーを生成します-

10 = 20;

定数は、プログラムの実行中に変更できない固定値を参照します。これらの固定値は、literals

定数は、整数定数、浮動定数、文字定数、文字列リテラルなどの基本的なデータ型のいずれかです。列挙定数もあります。

ザ・ constants 定義後に値を変更できないことを除いて、通常の変数と同じように扱われます。

整数リテラル

整数リテラルは、10進数、8進数、または16進数の定数にすることができます。接頭辞は、基数または基数を指定します。16進数の場合は0xまたは0X、8進数の場合は0、10進数の場合は何も指定しません。

整数リテラルには、unsignedとlongのそれぞれについて、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進形式または指数形式のいずれかで表すことができます。

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)のように表すために使用されます。ここに、そのようなエスケープシーケンスコードのいくつかのリストがあります-

エスケープシーケンス 意味
\\ \ キャラクター
\ ' ' キャラクター
\ " " キャラクター
\? ?キャラクター
\ a アラートまたはベル
\ b バックスペース
\ f フォームフィード
\ n 改行
\ r キャリッジリターン
\ t 水平タブ
\ v 垂直タブ
\ ooo 1〜3桁の8進数
\ xhh。。。 1桁以上の16進数

以下は、いくつかのエスケープシーケンス文字を示す例です-

#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言語は組み込みの演算子が豊富で、次のタイプの演算子を提供します-

  • 算術演算子
  • 関係演算子
  • 論理演算子
  • ビット演算子
  • 代入演算子
  • その他の演算子

このチュートリアルでは、算術、リレーショナル、論理、ビット単位、代入、およびその他の演算子を1つずつ説明します。

算術演算子

次の表は、Objective-C言語でサポートされているすべての算術演算子を示しています。変数を想定A 10と変数を保持します B 20を保持し、次に−

例を表示

オペレーター 説明
+ 2つのオペランドを追加します A + Bは30を与えます
- 最初のオペランドから2番目のオペランドを減算します A-Bは-10を与えます
* 両方のオペランドを乗算します A * Bは200を与えます
/ 分子を分母で割る B / Aは2を与えます
モジュラス演算子と整数除算後の余り B%Aは0を与えます
++ インクリメント演算子は整数値を1つ増やします A ++は11を与えます
- デクリメント演算子は整数値を1つ減らします A--は9を与えます

関係演算子

次の表は、Objective-C言語でサポートされているすべての関係演算子を示しています。変数を想定A 10と変数を保持します B 20を保持し、次に−

例を表示

オペレーター 説明
== 2つのオペランドの値が等しいかどうかをチェックします。はいの場合、条件は真になります。 (A == B)は真ではありません。
!= 2つのオペランドの値が等しいかどうかをチェックします。値が等しくない場合、条件は真になります。 (A!= B)は真です。
>> 左のオペランドの値が右のオペランドの値より大きいかどうかを確認します。はいの場合、条件は真になります。 (A> B)は正しくありません。
< 左のオペランドの値が右のオペランドの値よりも小さいかどうかを確認します。はいの場合、条件は真になります。 (A <B)は真です。
> = 左のオペランドの値が右のオペランドの値以上であるかどうかを確認します。はいの場合、条件は真になります。 (A> = B)は正しくありません。
<= 左のオペランドの値が右のオペランドの値以下であるかどうかをチェックします。はいの場合、条件は真になります。 (A <= B)は真です。

論理演算子

次の表は、Objective-C言語でサポートされているすべての論理演算子を示しています。変数を想定A 1と変数を保持します B 0を保持し、次に−

例を表示

オペレーター 説明
&& 論理AND演算子と呼ばれます。両方のオペランドがゼロ以外の場合、条件は真になります。 (A && B)は誤りです。
|| 論理OR演算子と呼ばれます。2つのオペランドのいずれかがゼロ以外の場合、条件は真になります。 (A || B)は真です。
論理NOT演算子と呼ばれます。オペランドの論理状態を逆にするために使用します。条件がtrueの場合、LogicalNOT演算子はfalseになります。 !(A && B)は真です。

ビット演算子

ビット単位の演算子はビットを処理し、ビットごとの演算を実行します。&、|、^の真理値表は次のとおりです-

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 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を保持すると仮定すると、-

例を表示

オペレーター 説明
バイナリAND演算子は、両方のオペランドに存在する場合、結果にビットをコピーします。 (A&B)は12、つまり00001100を与えます
| バイナリOR演算子は、いずれかのオペランドに存在する場合、ビットをコピーします。 (A | B)は61を与えます。これは00111101です。
^ バイナリXOR演算子は、ビットが両方ではなく一方のオペランドに設定されている場合、そのビットをコピーします。 (A ^ B)は49を返します。これは00110001です。
Binary Ones Complement Operatorは単項であり、ビットを「反転」させる効果があります。 (〜A)は-61を返します。これは、2の補数形式の11000011です。
<< バイナリ左シフト演算子。左のオペランドの値は、右のオペランドで指定されたビット数だけ左に移動します。 << 2は240、つまり11110000になります
>> バイナリ右シフト演算子。左のオペランドの値は、右のオペランドで指定されたビット数だけ右に移動します。 >> 2は15になります。これは00001111です。

代入演算子

Objective-C言語でサポートされている次の代入演算子があります-

例を表示

オペレーター 説明
= 単純な代入演算子、右側のオペランドから左側のオペランドに値を代入します C = A + Bは、A + Bの値をCに割り当てます
+ = AND代入演算子を追加します。これは、右のオペランドを左のオペランドに追加し、結果を左のオペランドに割り当てます。 C + = AはC = C + Aと同等です
-= AND代入演算子を減算します。左オペランドから右オペランドを減算し、その結果を左オペランドに代入します。 C- = AはC = C-Aと同等です
* = 乗算AND代入演算子。右のオペランドと左のオペランドを乗算し、その結果を左のオペランドに代入します。 C * = AはC = C * Aと同等です
/ = AND代入演算子を除算します。左オペランドを右オペランドで除算し、結果を左オペランドに代入します。 C / = AはC = C / Aと同等です
%= モジュラスAND代入演算子。2つのオペランドを使用してモジュラスを取り、その結果を左側のオペランドに割り当てます。 C%= AはC = C%Aと同等です
<< = 左シフトAND代入演算子 C << = 2はC = C << 2と同じです
>> = 右シフトAND代入演算子 C >> = 2はC = C >> 2と同じです
&= ビットごとのAND代入演算子 C&= 2はC = C&2と同じです
^ = ビット単位の排他的論理和と代入演算子 C ^ = 2はC = C ^ 2と同じです
| = ビット単位の包括的ORおよび代入演算子 C | = 2はC = C |と同じです 2

その他の演算子↦sizeof&ternary

を含む他のいくつかの重要な演算子があります sizeof そして ? : Objective-C言語でサポートされています。

例を表示

オペレーター 説明
のサイズ() 変数のサイズを返します。 sizeof(a)(aは整数)は4を返します。
変数のアドレスを返します。 &a; 変数の実際のアドレスを示します。
* 変数へのポインター。 * a; 変数へのポインタになります。
?: 条件式 条件が真の場合?次に値X:それ以外の場合は値Y

Objective-Cでのオペレーターの優先順位

演算子の優先順位は、式内の用語のグループ化を決定します。これは、式の評価方法に影響します。特定の演算子は他の演算子よりも優先されます。たとえば、乗算演算子は加算演算子よりも優先されます-

たとえば、x = 7 + 3 * 2; ここでは、演算子*の優先順位が+よりも高いため、xには20ではなく13が割り当てられます。したがって、最初に3 * 2が乗算され、次に7に加算されます。

ここでは、優先順位が最も高い演算子がテーブルの上部に表示され、優先順位が最も低い演算子が下部に表示されます。式内では、優先順位の高い演算子が最初に評価されます。

カテゴリー  オペレーター  結合性 
Postfix  ()[]->。++ ----   左から右へ 
単項  +-!〜++ ---(タイプ)*&sizeof  右から左へ 
乗法   * /%  左から右へ 
添加剤   +-  左から右へ 
シフト   << >>  左から右へ 
関連した   << = >> =  左から右へ 
平等   ==!=  左から右へ 
ビット単位のXOR  左から右へ 
ビットごとのOR  左から右へ 
論理積  &&  左から右へ 
論理OR  ||  左から右へ 
条件付き  ?:  右から左へ 
割り当て  = + =-= * = / =%= >> = << =&= ^ = | =  右から左へ 
コンマ  、  左から右へ 

コードのブロックを数回実行する必要がある場合があります。一般に、ステートメントは順番に実行されます。関数の最初のステートメントが最初に実行され、次に2番目のステートメントが実行されます。

プログラミング言語は、より複雑な実行パスを可能にするさまざまな制御構造を提供します。

ループステートメントを使用すると、ステートメントまたはステートメントのグループを複数回実行できます。以下は、ほとんどのプログラミング言語でのループステートメントの一般的な形式です。

Objective-Cプログラミング言語は、ループ要件を処理するために次のタイプのループを提供します。詳細を確認するには、次のリンクをクリックしてください。

シニア番号 ループの種類と説明
1 whileループ

指定された条件が真である間、ステートメントまたはステートメントのグループを繰り返します。ループ本体を実行する前に条件をテストします。

2 forループ

一連のステートメントを複数回実行し、ループ変数を管理するコードを省略します。

3 do ... whileループ

whileステートメントと同様ですが、ループ本体の最後で条件をテストする点が異なります。

4 ネストされたループ

while、for、またはdo..whileループ内で1つ以上のループを使用できます。

ループ制御ステートメント

ループ制御ステートメントは、実行を通常のシーケンスから変更します。実行がスコープを離れると、そのスコープで作成されたすべての自動オブジェクトが破棄されます。

Objective-Cは、次の制御ステートメントをサポートしています。詳細を確認するには、次のリンクをクリックしてください。

シニア番号 制御ステートメントと説明
1 breakステートメント

を終了します loop または switch ステートメントを実行し、ループまたはスイッチの直後のステートメントに実行を転送します。

2 ステートメントを続ける

ループに本体の残りの部分をスキップさせ、繰り返す前にすぐにその状態を再テストします。

無限ループ

条件がfalseにならない場合、ループは無限ループになります。ザ・forループは伝統的にこの目的のために使用されます。forループを形成する3つの式はいずれも必須ではないため、条件式を空のままにして無限ループを作成できます。

#import <Foundation/Foundation.h>
 
int main () {

   for( ; ; ) {
      NSLog(@"This loop will run forever.\n");
   }

   return 0;
}

条件式がない場合は、trueと見なされます。初期化とインクリメントの式があるかもしれませんが、Objective-Cプログラマーはより一般的にfor(;;)構文を使用して無限ループを示します。

意思決定構造では、プログラマーは、プログラムによって評価またはテストされる1つ以上の条件と、条件が真であると判断された場合に実行される1つまたは複数のステートメント、およびオプションで、条件が真である場合に実行される他のステートメントを指定する必要があります。 falseと判断されます。

以下は、ほとんどのプログラミング言語に見られる典型的な意思決定構造の一般的な形式です。

Objective-Cプログラミング言語は non-zero そして non-null としての値 true、そしてそれがどちらかである場合 zero または null、それからそれはとして仮定されます false 値。

Objective-Cプログラミング言語は、次のタイプの意思決定ステートメントを提供します。詳細を確認するには、次のリンクをクリックしてください-

シニア番号 ステートメントと説明
1 ifステートメント

アン if statement ブール式とそれに続く1つ以上のステートメントで構成されます。

2 if ... elseステートメント

アン if statement オプションの後に続くことができます else statement、ブール式がfalseの場合に実行されます。

3 ネストされたifステートメント

あなたは1つを使用することができます if または else if 別の内部のステートメント if または else if ステートメント。

4 switchステートメント

A switch ステートメントを使用すると、値のリストに対して変数が等しいかどうかをテストできます。

5 ネストされたswitchステートメント

あなたは1つを使用することができます switch 別の内部のステートメント switch ステートメント。

?:オペレーター

カバーしました conditional operator ? : 置き換えるために使用できる前の章で if...elseステートメント。それは次の一般的な形式を持っています-

Exp1 ? Exp2 : Exp3;

ここで、Exp1、Exp2、およびExp3は式です。コロンの使用と配置に注意してください。

?の値 式は次のように決定されます。Exp1が評価されます。trueの場合、Exp2が評価され、?全体の値になります。式。Exp1がfalseの場合、Exp3が評価され、その値が式の値になります。

関数は、一緒にタスクを実行するステートメントのグループです。すべてのObjective-Cプログラムには1つのC関数があります。main()、および最も些細なプログラムはすべて、追加の関数を定義できます。

コードを個別の関数に分割できます。コードをさまざまな関数にどのように分割するかはあなた次第ですが、論理的には通常、各関数が特定のタスクを実行するように分割されます。

機能 declaration関数の名前、戻り値の型、およびパラメーターについてコンパイラーに通知します。機能definition 関数の実際の本体を提供します。

基本的にObjective-Cでは、関数をメソッドとして呼び出します。

Objective-C Foundationフレームワークは、プログラムが呼び出すことができる多数の組み込みメソッドを提供します。たとえば、メソッドappendString() 文字列を別の文字列に追加します。

メソッドは、関数、サブルーチン、プロシージャなど、さまざまな名前で知られています。

メソッドの定義

Objective-Cプログラミング言語でのメソッド定義の一般的な形式は次のとおりです。

- (return_type) method_name:( argumentType1 )argumentName1 
joiningArgument2:( argumentType2 )argumentName2 ... 
joiningArgumentn:( argumentTypen )argumentNamen {
   body of the function
}

Objective-Cプログラミング言語のメソッド定義は、メソッドヘッダーメソッド本体で構成されています。これがメソッドのすべての部分です-

  • Return Type−メソッドは値を返す場合があります。ザ・return_type関数が返す値のデータ型です。一部のメソッドは、値を返さずに目的の操作を実行します。この場合、return_typeはキーワードですvoid

  • Method Name−これはメソッドの実際の名前です。メソッド名とパラメータリストが一緒になってメソッドシグネチャを構成します。

  • Arguments−引数はプレースホルダーのようなものです。関数が呼び出されると、引数に値を渡します。この値は、実際のパラメーターまたは引数と呼ばれます。パラメータリストは、メソッドの引数のタイプ、順序、および数を参照します。引数はオプションです。つまり、メソッドに引数を含めることはできません。

  • Joining Argument −結合引数は、読みやすくし、呼び出し中に明確にすることです。

  • Method Body −メソッド本体には、メソッドの機能を定義するステートメントのコレクションが含まれています。

以下は、と呼ばれるメソッドのソースコードです。 max()。このメソッドは、2つのパラメーターnum1とnum2を取り、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; 
}

メソッド宣言

方法 declaration関数名とメソッドの呼び出し方法についてコンパイラーに指示します。関数の実際の本体は個別に定義できます。

メソッド宣言には次の部分があります-

- (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;
}

max()関数をmain()関数と一緒に保持し、ソースコードをコンパイルしました。最終的な実行可能ファイルを実行すると、次の結果が生成されます-

2013-09-07 22:28:45.912 demo[26080] Max value is : 200

関数の引数

関数が引数を使用する場合は、引数の値を受け入れる変数を宣言する必要があります。これらの変数は、formal parameters 関数の。

仮パラメータは、関数内の他のローカル変数と同様に動作し、関数への入力時に作成され、終了時に破棄されます。

関数の呼び出し中に、引数を関数に渡す方法は2つあります-

シニア番号 通話の種類と説明
1 値で呼び出す

このメソッドは、引数の実際の値を関数の仮パラメーターにコピーします。この場合、関数内のパラメーターに加えられた変更は引数に影響を与えません。

2 参照による呼び出し

このメソッドは、引数のアドレスを仮パラメーターにコピーします。関数内では、アドレスは呼び出しで使用される実際の引数にアクセスするために使用されます。これは、パラメータに加えられた変更が引数に影響を与えることを意味します。

デフォルトでは、Objective-Cは call by value引数を渡す。一般に、これは、関数内のコードが関数の呼び出しに使用される引数を変更できないことを意味し、max()関数の呼び出し中の上記の例は同じメソッドを使用しました。

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を使用する簡単な例です。このサンプルに注意してくださいdoesn't workonline compiler今のところ。使用する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アプリケーションとMacOS Xでより多く使用されます。したがって、ブロックの使用法を理解することがより重要です。

Objective-Cプログラミング言語では、int、float、boolなどの基本的なデータ型をオブジェクト形式で保存するために、

Objective-Cは、NSNumberを操作するためのさまざまなメソッドを提供し、重要なメソッドを次の表に示します。

シニア番号 方法と説明
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オブジェクトを作成して返し、それを浮動小数点数として扱います。

5

+ (NSNumber *)numberWithInt:(int)value

指定された値を含むNSNumberオブジェクトを作成して返し、それをsignedintとして扱います。

6

+ (NSNumber *)numberWithInteger:(NSInteger)value

指定された値を含むNSNumberオブジェクトを作成して返し、NSIntegerとして扱います。

7

- (BOOL)boolValue

受信者の値をBOOLとして返します。

8

- (char)charValue

受信者の値をcharとして返します。

9

- (double)doubleValue

受信者の値をdoubleとして返します。

10

- (float)floatValue

レシーバーの値をfloatとして返します。

11

- (NSInteger)integerValue

受信者の値をNSIntegerとして返します。

12

- (int)intValue

受信者の値をintとして返します。

13

- (NSString *)stringValue

受信者の値を人間が読める文字列として返します。

これは、2つの数値を乗算して積を返すNSNumberを使用する簡単な例です。

#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プログラミング言語はと呼ばれるデータ構造を提供します the array、同じタイプの要素の固定サイズの順次コレクションを格納できます。配列はデータのコレクションを格納するために使用されますが、配列を同じタイプの変数のコレクションと考える方が便利な場合がよくあります。

number0、number1、...、number99などの個々の変数を宣言する代わりに、numbersなどの1つの配列変数を宣言し、numbers [0]、numbers [1]、...、numbers [99]を使用して表現します。個々の変数。配列内の特定の要素は、インデックスによってアクセスされます。

すべてのアレイは、連続したメモリ位置で構成されています。最小アドレスは最初の要素に対応し、最大アドレスは最後の要素に対応します。

配列の宣言

Objective-Cで配列を宣言するために、プログラマーは次のように配列に必要な要素のタイプと要素の数を指定します。

type arrayName [ arraySize ];

これは一次元配列と呼ばれます。ザ・arraySize ゼロより大きい整数定数である必要があり、 type任意の有効なObjective-Cデータ型にすることができます。たとえば、と呼ばれる10要素の配列を宣言するにはbalance タイプdoubleの場合、このステートメントを使用します-

double balance[10];

現在、balanceは可変配列であり、最大10個のdouble数を保持するのに十分です。

配列の初期化

次のように、Objective-Cで配列を1つずつ、または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の値を割り当てます。4番目のインデックスを持つ配列は5番目、つまり最後の要素になります。これは、すべての配列の最初の要素のインデックスが0であるためです。これは、ベースインデックスとも呼ばれます。以下は、上記で説明したのと同じアレイの図解です。

配列要素へのアクセス

要素には、配列名にインデックスを付けることでアクセスします。これは、配列名の後に角括弧内に要素のインデックスを配置することによって行われます。例-

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プログラマーにとって明らかな配列に関連するいくつかの重要な概念があります-

シニア番号 コンセプトと説明
1 多次元配列

Objective-Cは多次元配列をサポートしています。多次元配列の最も単純な形式は、2次元配列です。

2 関数に配列を渡す

インデックスなしで配列の名前を指定することにより、配列へのポインタを関数に渡すことができます。

3 関数から配列を返す

Objective-Cを使用すると、関数は配列を返すことができます。

4 配列へのポインタ

インデックスなしで配列名を指定するだけで、配列の最初の要素へのポインタを生成できます。

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

これで、メモリアドレスとは何か、それにアクセスする方法を理解したので、概念の基本は終わりました。それでは、ポインタとは何かを見てみましょう。

ポインタとは何ですか?

A pointerは、値が別の変数のアドレス、つまりメモリ位置の直接アドレスである変数です。他の変数や定数と同様に、変数アドレスを格納するために使用する前に、ポインターを宣言する必要があります。ポインタ変数宣言の一般的な形式は次のとおりです。

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プログラマーにとって明らかなはずです。

シニア番号 コンセプトと説明
1 Objective-C-ポインタ演算

ポインタで使用できる算術演算子は、++、-、+、-の4つです。

2 Objective-C-ポインタの配列

多数のポインターを保持する配列を定義できます。

3 Objective-C-ポインタへのポインタ

Objective-Cを使用すると、ポインタの上にポインタを置くことができます。

4 Objective-Cの関数へのポインタの受け渡し

参照またはアドレスの両方で引数を渡すと、渡された引数を、呼び出された関数によって呼び出し元の関数で変更できます。

5 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は、文字列を操作するためのさまざまな方法をサポートしています-

シニア番号 方法と目的
1

- (NSString *)capitalizedString;

受信者の大文字の表現を返します。

2

- (unichar)characterAtIndex:(NSUInteger)index;

指定された配列位置の文字を返します。

3

- (double)doubleValue;

受信者のテキストの浮動小数点値をdoubleとして返します。

4

- (float)floatValue;

受信者のテキストの浮動小数点値をfloatとして返します。

5

- (BOOL)hasPrefix:(NSString *)aString;

指定された文字列がレシーバーの開始文字と一致するかどうかを示すブール値を返します。

6

- (BOOL)hasSuffix:(NSString *)aString;

指定された文字列がレシーバーの終了文字と一致するかどうかを示すブール値を返します。

7

- (id)initWithFormat:(NSString *)format ...;

指定されたフォーマット文字列をテンプレートとして使用して初期化されたNSStringオブジェクトを返し、残りの引数値が代入されます。

8

- (NSInteger)integerValue;

受信者のテキストのNSInteger値を返します。

9

- (BOOL)isEqualToString:(NSString *)aString;

リテラルUnicodeベースの比較を使用して、指定された文字列がレシーバーと等しいかどうかを示すブール値を返します。

10

- (NSUInteger)length;

レシーバーのUnicode文字数を返します。

11

- (NSString *)lowercaseString;

受信者の小文字表現を返します。

12

- (NSRange)rangeOfString:(NSString *)aString;

レシーバー内で指定された文字列が最初に出現する範囲を検索して返します。

13

- (NSString *)stringByAppendingFormat:(NSString *)format ...;

指定されたフォーマット文字列と次の引数から構築された文字列をレシーバーに追加して作成された文字列を返します。

14

- (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set;

指定された文字セットに含まれるレシーバー文字の両端から削除された新しい文字列を返します。

15

- (NSString *)substringFromIndex:(NSUInteger)anIndex;

指定されたインデックスの文字列から最後までの受信機の文字を含む新しい文字列を返します。

次の例では、上記の機能のいくつかを使用しています-

#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関連のメソッドの完全なリストは、NSStringクラスリファレンスにあります。

Objective-C配列を使用すると、同じ種類の複数のデータ項目を保持できる変数のタイプを定義できますが、 structure は、Objective-Cプログラミングで使用できるもう1つのユーザー定義データ型であり、さまざまな種類のデータ項目を組み合わせることができます。

構造はレコードを表すために使用されます。図書館で本を追跡したいとします。各本に関する次の属性を追跡することをお勧めします-

  • Title
  • Author
  • Subject
  • ブックID

構造の定義

構造を定義するには、を使用する必要があります structステートメント。structステートメントは、プログラムに複数のメンバーを含む新しいデータ型を定義します。構造体ステートメントの形式は次のとおりです-

struct [structure tag] {
   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];

ザ・ structure tagオプションであり、各メンバー定義はintiなどの通常の変数定義です。またはfloatf; またはその他の有効な変数定義。構造体の定義の最後、最後のセミコロンの前に、1つ以上の構造体変数を指定できますが、これはオプションです。これがあなたが本の構造を宣言する方法です-

struct Books {
   NSString *title;
   NSString *author;
   NSString *subject;
   int   book_id;
} book;

構造体メンバーへのアクセス

構造体の任意のメンバーにアクセスするには、 member access operator (.)。メンバーアクセス演算子は、構造体変数名とアクセスする構造体メンバーの間のピリオドとしてコード化されます。あなたは使用します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

ビットフィールド

ビットフィールドを使用すると、構造体にデータをパックできます。これは、メモリまたはデータストレージが貴重な場合に特に役立ちます。典型的な例-

  • いくつかのオブジェクトをマシンワードにパックします。たとえば、1ビットフラグを圧縮できます。

  • 外部ファイル形式の読み取り-非標準のファイル形式を読み込むことができます。たとえば、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には6つのメンバーが含まれています。4つの1ビットフラグf1..f3、4ビットタイプおよび9ビットmy_intです。

Objective-Cは、フィールドの最大長がコンピューターの整数ワード長以下である場合、上記のビットフィールドを可能な限りコンパクトに自動的にパックします。そうでない場合、一部のコンパイラはフィールドのメモリオーバーラップを許可し、他のコンパイラは次のフィールドを次のワードに格納する場合があります。

ザ・ Objective-C Preprocessorはコンパイラの一部ではありませんが、コンパイルプロセスの別のステップです。簡単に言うと、Objective-Cプリプロセッサは単なるテキスト置換ツールであり、実際のコンパイルの前に必要な前処理を行うようにコンパイラに指示します。Objective-CプリプロセッサをOCPPと呼びます。

すべてのプリプロセッサコマンドはポンド記号(#)で始まります。これは最初の空白以外の文字である必要があり、読みやすくするために、プリプロセッサディレクティブは最初の列で開始する必要があります。次のセクションでは、すべての重要なプリプロセッサディレクティブを一覧表示します-

シニア番号 指令と説明
1

#define

プリプロセッサマクロを置き換えます

2

#include

別のファイルから特定のヘッダーを挿入します

3

#undef

プリプロセッサマクロの定義を解除します

4

#ifdef

このマクロが定義されている場合はtrueを返します

5

#ifndef

このマクロが定義されていない場合はtrueを返します

6

#if

コンパイル時の条件が真であるかどうかをテストします

7

#else

#ifの代替

8

#elif

#else #if in one statement

9

#endif

プリプロセッサを条件付きで終了します

10

#error

stderrにエラーメッセージを出力します

11

#pragma

標準化された方法を使用してコンパイラーに特別なコマンドを発行します

プリプロセッサの例

次の例を分析して、さまざまなディレクティブを理解してください。

#define MAX_ARRAY_LENGTH 20

このディレクティブは、MAX_ARRAY_LENGTHのインスタンスを20に置き換えるようにOCPPに指示します。読みやすさを向上させるために定数に#defineを使用します。

#import <Foundation/Foundation.h>
#include "myheader.h"

これらのディレクティブは、OCPPにfoundation.hを取得するように指示します。 Foundation Frameworkテキストを現在のソースファイルに追加します。次の行は、OCPPに取得するように指示しますmyheader.h ローカルディレクトリからコンテンツを現在のソースファイルに追加します。

#undef  FILE_SIZE
#define FILE_SIZE 42

これは、OCPPに既存のFILE_SIZEの定義を解除し、42として定義するように指示します。

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

これは、MESSAGEがまだ定義されていない場合にのみ、MESSAGEを定義するようにOCPPに指示します。

#ifdef DEBUG
   /* Your debugging statements here */
#endif

これは、DEBUGが定義されている場合、囲まれたステートメントを処理するようにOCPPに指示します。これは、コンパイル時に-DDEBUGフラグをgccコンパイラーに渡す場合に役立ちます。これによりDEBUGが定義されるため、コンパイル中にオンザフライでデバッグのオンとオフを切り替えることができます。

事前定義されたマクロ

ANSI Cは、いくつかのマクロを定義しています。それぞれをプログラミングで使用できますが、事前定義されたマクロを直接変更しないでください。

シニア番号 マクロと説明
1

__DATE__

「MMMDDYYYY」形式の文字リテラルとしての現在の日付

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つの別々のトークンを1つのトークンに結合できます。例-

#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を使用して定義されているかどうかを判別します。指定された識別子が定義されている場合、値は真(ゼロ以外)です。シンボルが定義されていない場合、値は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、タイプに新しい名前を付けるために使用できます。以下は、用語を定義する例ですBYTE 1バイトの数値の場合-

typedef unsigned char BYTE;

このタイプ定義の後、識別子BYTEをタイプの省略形として使用できます。 unsigned char, for example:

BYTE  b1, b2;

慣例により、これらの定義には大文字を使用して、型名が実際には記号の省略形であることをユーザーに通知しますが、次のように小文字を使用できます。

typedef unsigned char byte;

使用できます typedefユーザー定義のデータ型にも名前を付けます。たとえば、typedefとstructureを使用して新しいデータ型を定義し、そのデータ型を使用して次のように構造変数を直接定義できます。

#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 = @"TutorialsPoint";
   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 : TutorialsPoint
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と#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

型キャストは、変数をあるデータ型から別のデータ型に変換する方法です。たとえば、long値を単純な整数に格納する場合は、cast long tointと入力できます。を使用して、値をあるタイプから別のタイプに明示的に変換できます。cast operator 次のように-

(type_name) expression

Objective-Cでは、通常、浮動小数点演算を行うためにCGFloatを使用します。これは、32ビットの場合は基本タイプのfloatから派生し、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 そして最後にそれはカウントで除算されてdouble値を生成します。

型変換は、コンパイラーによって自動的に実行される暗黙的なものにすることも、を使用して明示的に指定することもできます。 cast operator。型変換が必要な場合は常にキャスト演算子を使用することをお勧めします。

整数拡張

整数拡張は、整数型の値が「より小さい」よりも小さいプロセスです。 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になります。

通常の算術変換

ザ・ usual arithmetic conversions値を共通の型にキャストするために暗黙的に実行されます。コンパイラは最初に整数拡張を実行します。オペランドの型がまだ異なる場合は、次の階層で最上位に表示される型に変換されます。

通常の算術変換は、代入演算子に対しても、論理演算子&&および||に対しても実行されません。概念を理解するために次の例を見てみましょう-

#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の結果を生成します。

NSLogメソッド

ログを印刷するために、HelloWorldの例から直接使用したObjective-Cプログラミング言語のNSLogメソッドを使用します。

「HelloWorld」という単語を出力する簡単なコードを見てみましょう-

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"Hello, World! \n");
   return 0;
}

これで、プログラムをコンパイルして実行すると、次の結果が得られます。

2013-09-16 00:32:50.888 demo[16669] Hello, World!

ライブアプリのログを無効にする

アプリケーションで使用するNSLogは、デバイスのログに出力されるため、ライブビルドでログを印刷するのは適切ではありません。したがって、ログの印刷には型定義を使用し、以下に示すように使用できます。

#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プログラミングでは、エラー処理はで利用可能なNSErrorクラスで提供されます Foundation framework.

NSErrorオブジェクトは、エラーコードまたはエラー文字列のみを使用した場合よりも豊富で拡張可能なエラー情報をカプセル化します。NSErrorオブジェクトのコア属性は、エラードメイン(文字列で表される)、ドメイン固有のエラーコード、およびアプリケーション固有の情報を含むユーザー情報ディクショナリです。

NSError

Objective-Cプログラムは、NSErrorオブジェクトを使用して、ユーザーに通知する必要のあるランタイムエラーに関する情報を伝達します。ほとんどの場合、プログラムはこのエラー情報をダイアログまたはシートに表示します。ただし、情報を解釈して、ユーザーにエラーからの回復を試みるか、エラーを自分で修正するように依頼する場合もあります。

NSErrorオブジェクトは次のもので構成されます-

  • Domain −エラードメインは、事前定義されたNSErrorドメインのいずれかであるか、カスタムドメインを説明する任意の文字列であり、ドメインはnilであってはなりません。

  • Code −エラーのエラーコード。

  • User Info −エラーおよび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プログラムにいくつかの値を渡すことができます。これらの値はと呼ばれますcommand line arguments 多くの場合、これらはプログラムにとって重要です。特に、コード内でこれらの値をハードコーディングするのではなく、外部からプログラムを制御する場合に重要です。

コマンドライン引数は、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");
   }
}

上記のコードをコンパイルして、「テスト」などの単一の引数を使用して実行すると、次の結果が生成されます。

2013-09-13 03:01:17.333 demo[7640] The argument supplied is testing

上記のコードを2つの引数、たとえばtesting1とtesting2を使用してコンパイルおよび実行すると、次の結果が生成されます。

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プログラミング言語の主な目的はCプログラミング言語にオブジェクト指向を追加することであり、クラスはオブジェクト指向プログラミングをサポートするObjective-Cの中心的な機能であり、多くの場合ユーザー定義型と呼ばれます。

クラスはオブジェクトの形式を指定するために使用され、データ表現とそのデータを操作するためのメソッドを1つのきちんとしたパッケージに結合します。クラス内のデータとメソッドは、クラスのメンバーと呼ばれます。

Objective-Cの特性

  • クラスは2つの異なるセクションで定義されています。 @interface そして @implementation

  • ほとんどすべてがオブジェクトの形をしています。

  • オブジェクトはメッセージを受信し、オブジェクトはしばしば受信者と呼ばれます。

  • オブジェクトにはインスタンス変数が含まれています。

  • オブジェクトとインスタンス変数にはスコープがあります。

  • クラスはオブジェクトの実装を隠します。

  • プロパティは、他のクラスのクラスインスタンス変数へのアクセスを提供するために使用されます。

Objective-Cクラスの定義

クラスを定義するときは、データ型の青写真を定義します。これは実際にはデータを定義しませんが、クラス名の意味、つまり、クラスのオブジェクトが何で構成され、そのようなオブジェクトに対してどのような操作を実行できるかを定義します。

クラス定義はキーワードで始まります @interfaceその後にインターフェース(クラス)名が続きます。中括弧のペアで囲まれたクラス本体。Objective-Cでは、すべてのクラスはと呼ばれる基本クラスから派生しています。NSObject。これは、すべてのObjective-Cクラスのスーパークラスです。メモリの割り当てや初期化などの基本的な方法を提供します。たとえば、キーワードを使用してBoxデータ型を定義しましたclass 次のように-

@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、これはキーワードです

  • その後に、非アトミックまたはアトミック、読み取り/書き込み専用、およびstrong、unsafe_unretained、またはweakのアクセス指定子が続きます。これは、変数のタイプによって異なります。どのポインタタイプでも、strong、unsafe_unretained、またはweakを使用できます。同様に、他のタイプについても、読み取り/書き込みまたは読み取り専用を使用できます。

  • この後に変数のデータ型が続きます。

  • 最後に、プロパティ名をセミコロンで終了します。

  • 実装クラスにsynthesisステートメントを追加できます。ただし、最新のXCodeでは、合成部分はXCodeによって処理されるため、合成ステートメントを含める必要はありません。

クラスのインスタンス変数にアクセスできるプロパティでのみ可能です。実際には、内部的にgetterメソッドとsetterメソッドがプロパティに対して作成されます。

たとえば、プロパティがあるとしましょう @property (nonatomic ,readonly ) BOOL isDone。内部には、以下のように作成されたセッターとゲッターがあります。

-(void)setIsDone(BOOL)isDone;
-(BOOL)isDone;

オブジェクト指向プログラミングで最も重要な概念の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

アクセス制御と継承

派生クラスは、インターフェイスクラスで定義されている場合、基本クラスのすべてのプライベートメンバーにアクセスできますが、実装ファイルで定義されているプラ​​イベートメンバーにはアクセスできません。

次の方法で、誰がアクセスできるかによって、さまざまなアクセスタイプを要約できます。

派生クラスは、次の例外を除いて、すべての基本クラスのメソッドと変数を継承します-

  • 拡張機能を使用して実装ファイルで宣言された変数にはアクセスできません。

  • 拡張機能を使用して実装ファイルで宣言されたメソッドにはアクセスできません。

  • 継承されたクラスが基本クラスのメソッドを実装する場合、派生クラスのメソッドが実行されます。

言葉 polymorphism多くの形を持つことを意味します。通常、ポリモーフィズムは、クラスの階層があり、それらが継承によって関連付けられている場合に発生します。

Objective-Cのポリモーフィズムとは、メンバー関数を呼び出すと、関数を呼び出すオブジェクトのタイプに応じて異なる関数が実行されることを意味します。

例を考えてみましょう。すべてのシェイプの基本的なインターフェイスを提供するクラスShapeがあります。SquareとRectangleは、基本クラスShapeから派生しています。

OOP機能について表示するメソッドprintAreaがあります polymorphism

#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

上記の例では、メソッドcalculateAreaおよびprintAreaの可用性に基づいて、基本クラスのメソッドまたは派生クラスのいずれかが実行されました。

ポリモーフィズムは、2つのクラスのメソッド実装に基づいて、基本クラスと派生クラスの間のメソッドの切り替えを処理します。

すべてのObjective-Cプログラムは、次の2つの基本要素で構成されています。

  • Program statements (code) −これは、アクションを実行するプログラムの一部であり、メソッドと呼ばれます。

  • Program data −データは、プログラム機能の影響を受けるプログラムの情報です。

カプセル化は、データとデータを操作する関数を結合し、外部からの干渉や誤用から安全に保つオブジェクト指向プログラミングの概念です。データのカプセル化は、次の重要なOOP概念につながりました。data hiding

Data encapsulation データとそれを使用する関数をバンドルするメカニズムであり、 data abstraction は、インターフェイスのみを公開し、実装の詳細をユーザーから隠すメカニズムです。

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 外の世界からは隠されているものですが、クラスが適切に機能するために必要です。

設計戦略

私たちのほとんどは、本当に公開する必要がない限り、デフォルトでクラスメンバーをプライベートにすることを苦い経験から学びました。それはいいですencapsulation

データのカプセル化は、Objective-Cを含むすべてのオブジェクト指向プログラミング(OOP)言語のコア機能の1つであるため、理解することが重要です。

特定の状況でのみ役立つ動作を追加して、既存のクラスを拡張したい場合があります。そのような拡張機能を既存のクラスに追加するために、Objective-Cはcategories そして 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 TutorialsPoint.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 TutorialsPoint.com 2013

カテゴリによって追加されたメソッドは、クラスとそのサブクラスのすべてのインスタンスで使用できますが、追加のメソッドを使用するソースコードファイルにカテゴリヘッダーファイルをインポートする必要があります。そうしないと、次のようになります。コンパイラの警告とエラー。

この例では、クラスが1つしかないため、ヘッダーファイルをインクルードしていません。このような場合は、上記のようにヘッダーファイルをインクルードする必要があります。

Objective-Cでのポーズについて始める前に、ポーズは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操作全体で影響を受けます。

クラス拡張はカテゴリとある程度類似していますが、コンパイル時にソースコードがあるクラスにのみ追加できます(クラスはクラス拡張と同時にコンパイルされます)。

クラス拡張によって宣言されたメソッドは、元のクラスの実装ブロックに実装されるため、たとえば、CocoaやNSStringなどのCocoaTouchクラスなどのフレームワーククラスでクラス拡張を宣言することはできません。

拡張機能は、実際にはカテゴリ名のないカテゴリです。それはしばしば呼ばれますanonymous categories

拡張機能を宣言する構文は、標準の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を使用すると、特定の状況で使用されると予想されるメソッドを宣言するプロトコルを定義できます。プロトコルは、プロトコルに準拠したクラスで実装されます。

簡単な例は、ネットワーク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では、すべてのメソッドが実行時に動的に解決されます。実行される正確なコードは、メソッド名(セレクター)と受信オブジェクトの両方によって決定されます。

動的バインディングにより、ポリモーフィズムが可能になります。たとえば、RectangleやSquareなどのオブジェクトのコレクションについて考えてみます。各オブジェクトには、printAreaメソッドの独自の実装があります。

次のコードフラグメントでは、式[anObjectprintArea]によって実行される実際のコードが実行時に決定されます。ランタイムシステムは、実行されるメソッドのセレクターを使用して、オブジェクトのクラスが何であれ、適切なメソッドを識別します。

動的バインディングを説明する簡単なコードを見てみましょう。

#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メソッドは実行時に動的に選択されます。これは動的バインディングの例であり、同様の種類のオブジェクトを処理する多くの状況で非常に役立ちます。

オブジェクトをその中に埋め込むクラスを定義するクラスクラスター内にサブクラスを作成できます。これらのクラスオブジェクトは複合オブジェクトです。

したがって、クラスクラスターとは何か疑問に思われるかもしれません。したがって、最初にクラスクラスターとは何かを確認します。

クラスクラスター

クラスクラスターは、Foundationフレームワークが広範囲に使用するデザインパターンです。クラスクラスターは、パブリック抽象スーパークラスの下にいくつかのプライベート具象サブクラスをグループ化します。このようにクラスをグループ化すると、機能の豊富さを損なうことなく、オブジェクト指向フレームワークの公開されているアーキテクチャが簡素化されます。クラスクラスターは、AbstractFactoryデザインパターンに基づいています。

簡単にするために、同様の関数に対して複数のクラスを作成する代わりに、入力の値に基づいて処理を処理する単一のクラスを作成します。

たとえば、NSNumberには、char、int、boolなどのクラスのクラスターが多数あります。それらすべてを単一のクラスにグループ化し、単一のクラスで同様の操作を処理します。NSNumberは、実際にはこれらのプリミティブ型の値をオブジェクトにラップします。

では、正確に複合オブジェクトとは何ですか?

独自の設計のオブジェクトにプライベートクラスターオブジェクトを埋め込むことにより、複合オブジェクトを作成します。この複合オブジェクトは、その基本機能をクラスターオブジェクトに依存でき、複合オブジェクトが特定の方法で処理したいメッセージのみをインターセプトします。このアーキテクチャにより、作成する必要のあるコードの量が減り、FoundationFrameworkによって提供されるテスト済みのコードを利用できるようになります。

これを次の図で説明します。

複合オブジェクトは、それ自体がクラスターの抽象スーパークラスのサブクラスであることを宣言する必要があります。サブクラスとして、スーパークラスのプリミティブメソッドをオーバーライドする必要があります。派生メソッドをオーバーライドすることもできますが、派生メソッドはプリミティブメソッドを介して機能するため、これは必要ありません。

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オブジェクトを追加できないことがわかります。しかし、検証配列がそれを処理します。同様に、配列を検証する各メソッドは、通常の一連の操作とは別に検証プロセスを追加します。

Appleのドキュメントを参照すると、以下に示すFoundationフレームワークの詳細を確認できます。

Foundationフレームワークは、Objective-Cクラスの基本レイヤーを定義します。有用なプリミティブオブジェクトクラスのセットを提供することに加えて、Objective-C言語でカバーされていない機能を定義するいくつかのパラダイムを導入します。Foundationフレームワークは、これらの目標を念頭に置いて設計されています-

  • 基本的なユーティリティクラスの小さなセットを提供します。

  • 割り当て解除などの一貫した規則を導入することにより、ソフトウェア開発を容易にします。

  • Unicode文字列、オブジェクトの永続性、およびオブジェクトの配布をサポートします。

  • 移植性を高めるために、OSの独立性のレベルを提供します。

フレームワークはAppleが買収したNeXTStepによって開発され、これらの基礎クラスはMac OSXとiOSの一部になりました。

NeXTStepによって開発されたため、クラスプレフィックスは「NS」です。

すべてのサンプルプログラムでFoundationFrameworkを使用しました。FoundationFrameworkを使用することはほぼ必須です。

一般的に、私たちは次のようなものを使用します #import <Foundation/NSString.h> Objective-Cクラスをインポートしますが、あまりにも多くのクラスをインポートしないようにするために、すべてがインポートされます。 #import <Foundation/Foundation.h>

NSObjectは、ファンデーションキットクラスを含むすべてのオブジェクトの基本クラスです。これは、メモリ管理の方法を提供します。また、ランタイムシステムへの基本的なインターフェイスとObjective-Cオブジェクトとして動作する機能も提供します。基本クラスはなく、すべてのクラスのルートです。

機能に基づく基礎クラス

シニア番号 ループの種類と説明
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 URL読み込みシステム

一般的なインターネットプロトコルへのアクセスを提供するクラスとプロトコルのセット。

高速列挙は、コレクションを列挙するのに役立つObjective-Cの機能です。したがって、高速列挙について知るためには、最初にコレクションについて知る必要があります。これについては、次のセクションで説明します。

Objective-Cのコレクション

コレクションは基本的な構成要素です。他のオブジェクトを保持および管理するために使用されます。コレクションの全体的な目的は、オブジェクトを効率的に格納および取得するための一般的な方法を提供することです。

コレクションにはいくつかの種類があります。それらはすべて、他のオブジェクトを保持できるという同じ目的を果たしますが、オブジェクトの取得方法がほとんど異なります。Objective-Cで使用される最も一般的なコレクションは次のとおりです。

  • NSSet
  • NSArray
  • NSDictionary
  • NSMutableSet
  • NSMutableArray
  • NSMutableDictionary

これらの構造について詳しく知りたい場合は、FoundationFrameworkのデータストレージを参照してください。

高速列挙構文

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

出力からわかるように、配列内の各オブジェクトは出力されますが、通常の高速列挙とは逆の順序になっています。

メモリ管理は、あらゆるプログラミング言語で最も重要なプロセスの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であり、元のオブジェクトの保持カウントではありません。これは、図の点線で表されています。

コピーされたオブジェクトは、releaseメソッドを使用してクラスCによって解放され、保持カウントが0になるため、オブジェクトは破棄されます。

最初のクラスAオブジェクトの場合、保持カウントは2であり、破棄するには2回解放する必要があります。これは、クラスAとクラスBのリリースステートメントによって実行され、保持カウントがそれぞれ1と0に減少します。最後に、オブジェクトは破棄されます。

MRRの基本ルール

  • 作成するオブジェクトはすべて所有します。名前が「alloc」、「new」、「copy」、または「mutableCopy」で始まるメソッドを使用してオブジェクトを作成します。

  • 保持を使用してオブジェクトの所有権を取得できます。受信したオブジェクトは通常、受信したメソッド内で有効なままであることが保証され、そのメソッドはオブジェクトを呼び出し元に安全に返すこともできます。2つの状況でretainを使用します-

    • アクセサメソッドまたは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の詳細については、「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