Objective-Cで継承しよう!初心者向けの完全ガイド10選 – Japanシーモア

Objective-Cで継承しよう!初心者向けの完全ガイド10選

Objective-C継承の基本と応用方法を解説するイラストObjctive-C
この記事は約22分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

このサービスは複数のSSPによる協力の下、運営されています。

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Objective-Cの継承は、初心者にとっては難しいテーマの一つと感じるかもしれません。

しかし、実際にはその背後にある考え方や基本的な実装は非常にシンプルです。

この記事では、初心者でもわかるObjective-Cの継承に関する全てを徹底解説します。

10の詳細なサンプルコードを通じて、継承の使い方から応用例、注意点まで解説していきます。

これからObjective-Cの継承について学ぶすべての方に、この記事が最良のガイドとなることを願っています。

●Objective-Cとは

Objective-Cは、C言語にオブジェクト指向プログラミングの概念を取り入れた言語として、1980年代に登場しました。

AppleのiOSやmacOSの開発で主要な役割を果たしてきた言語であり、その後Swiftに取って代わられるまでの間、数多くのアプリケーションがObjective-Cで書かれてきました。

Objective-Cは、メッセージベースの動的なメソッド呼び出しや、独特の文法が特徴です。

特に、メソッドの呼び出しは、他の多くの言語とは異なる形式をとります。

例えば、[object method]のような形で、オブジェクトにメッセージを送るという形になります。

○Objective-Cの基本概念

Objective-Cを理解するためには、いくつかの基本概念を押さえておくことが重要です。

ここでは、その中でも特に重要な概念をいくつかピックアップして紹介します。

  • オブジェクト:Objective-Cでは、データや振る舞いを持つ実体をオブジェクトとして扱います。オブジェクトは、クラスという設計図を元に生成されます。
  • クラス:オブジェクトの設計図としての役割を果たします。クラスにはプロパティやメソッドが定義され、これらはオブジェクトに継承されることで利用可能になります。
  • プロパティ:オブジェクトが持つデータの一部です。例えば、人のオブジェクトであれば、名前や年齢といった属性がプロパティとして考えられます。
  • メソッド:オブジェクトが持つ振る舞いの一部です。オブジェクトが実行可能な動作をメソッドとして定義します。例えば、人のオブジェクトであれば、話す、歩くなどの動作がメソッドとして考えられます。

●継承とは

継承は、プログラミングの中で非常に基本的かつ強力な概念の一つです。

継承を使用することで、既存のクラスの属性やメソッドを新しいクラスに引き継ぐことができます。

これにより、コードの再利用や拡張が簡単になります。

Objective-Cにおける継承は、クラス間で属性や動作を共有するための主要な手段として使用されます。

一つのクラス(親クラス、またはスーパークラスとも呼ばれる)の特性を別のクラス(子クラス、またはサブクラスとも呼ばれる)が受け継ぐことによって、新しいクラスは親クラスの特性をそのまま利用できるようになります。

○継承の意義と基本的な使い方

継承の最大の意義は、コードの再利用です。

あるクラスに定義されている属性やメソッドを、新しいクラスで再度定義することなく利用できるため、コードの重複を避け、プログラムのメンテナンスも容易になります。

また、継承を活用することで、既存のクラスをベースにして新しい機能を追加したり、既存の動作をカスタマイズしたりすることが可能になります。

これにより、システム全体の設計が柔軟になり、変更や拡張が容易に実施できるようになります。

Objective-Cでの継承の基本的な使い方は、新しいクラスを定義する際に親クラスを指定することで行います。

これにより、新しいクラスは親クラスの全ての属性やメソッドを引き継ぐことになります。

しかし、単に継承を行うだけでなく、継承したクラスを適切に利用し、必要に応じてカスタマイズすることが、継承を有効に使うためのキーとなります。

●Objective-Cの継承の使い方

Objective-Cのプログラミングにおいて、継承は非常に重要な概念です。

継承を理解し、適切に活用することで、効率的なプログラム設計が可能になります。

ここでは、Objective-Cの継承に関して、基本的な使い方から応用例、注意点までを詳細に解説していきます。

○サンプルコード1:基本的な継承の実装

まずは、継承の基本的な使い方をサンプルコードを通じて学びましょう。

// 親クラスとしてAnimalクラスを定義
@interface Animal : NSObject
- (void) speak;
@end

@implementation Animal
- (void) speak {
    NSLog(@"Animal speaks");
}
@end

// Animalクラスを継承したDogクラスを定義
@interface Dog : Animal
@end

@implementation Dog
- (void) speak {
    NSLog(@"Dog barks");
}
@end

このコードでは、Animalという親クラスを定義しており、その子クラスとしてDogを定義しています。

DogクラスはAnimalクラスのspeaksメソッドをオーバーライドして、独自の振る舞いを持たせています。

この例を実行すると、Dogクラスのインスタンスが「Dog barks」と出力します。

親クラスのメソッドが子クラスによって上書きされていることがわかります。

○サンプルコード2:オーバーライドを利用したメソッドの変更

次に、オーバーライドを利用してメソッドの振る舞いを変更する方法を見ていきましょう。

@interface Cat : Animal
@end

@implementation Cat
- (void) speak {
    [super speak];
    NSLog(@"Cat meows");
}
@end

こちらのコードでは、Animalクラスを継承した新たな子クラスCatを定義しています。

Catクラスでは、親クラスのspeakメソッドを呼び出した上で、独自のメソッドを追加しています。

この例を実行すると、Catクラスのインスタンスは「Animal speaks」の後に「Cat meows」と出力します。

親クラスのメソッドを利用しつつ、新たな振る舞いを追加することができることが確認できます。

○サンプルコード3:superキーワードを用いた親クラスのメソッド呼び出し

Objective-Cにおける継承では、子クラスが親クラスのメソッドをオーバーライドした際、オリジナルの親クラスのメソッドを呼び出す必要がある場合があります。

このとき、superキーワードを使用することで親クラスのメソッドを呼び出すことができます。

このコードでは、親クラス「Animal」があり、子クラス「Dog」がそれを継承しています。

DogクラスはAnimalクラスのspeakメソッドをオーバーライドしており、その中でsuperキーワードを使用して、Animalクラスのspeakメソッドを呼び出しています。

#import <Foundation/Foundation.h>

@interface Animal : NSObject
- (void)speak;
@end

@implementation Animal
- (void)speak {
    NSLog(@"Animal speaks");
}
@end

@interface Dog : Animal
- (void)speak;
@end

@implementation Dog
- (void)speak {
    [super speak];
    NSLog(@"Dog barks");
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Dog *myDog = [[Dog alloc] init];
        [myDog speak];
    }
    return 0;
}

この例では、Dogクラスのspeakメソッドを呼び出すと、まず親クラスのspeakメソッドが呼び出され、その後に子クラスのspeakメソッドが呼び出されることになります。

そのため、実行結果としては次のように出力されます。

Animal speaks
Dog barks

○サンプルコード4:複数の子クラスからの継承

Objective-Cでは、1つの親クラスから複数の子クラスを継承することはできません。

しかし、1つの子クラスが複数の親クラスからのメソッドやプロパティを継承することは、プロトコルを使用することで可能です。

しかし、直接の複数継承はサポートされていません。

このコードでは、「Person」クラスと「Employee」クラスがあり、EmployeeクラスがPersonクラスを継承しています。

さらに、Employeeクラスは別のクラス「Manager」からも継承されています。

#import <Foundation/Foundation.h>

@interface Person : NSObject
@property NSString *name;
- (void)introduce;
@end

@implementation Person
- (void)introduce {
    NSLog(@"Hello, my name is %@", self.name);
}
@end

@interface Employee : Person
@property NSString *jobTitle;
- (void)introduce;
@end

@implementation Employee
- (void)introduce {
    [super introduce];
    NSLog(@"I am a %@", self.jobTitle);
}
@end

@interface Manager : Employee
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Manager *manager = [[Manager alloc] init];
        manager.name = @"John";
        manager.jobTitle = @"Project Manager";
        [manager introduce];
    }
    return 0;
}

この例では、ManagerクラスはEmployeeクラスとPersonクラスの両方のメソッドとプロパティを継承しています。

実行結果としては次のように出力されます。

Hello, my name is John
I am a Project Manager

●Objective-Cの継承の応用例

Objective-Cの継承は、基本的な使い方だけでなく、より高度なテクニックと組み合わせることで、多様なプログラムを実現することが可能です。

ここでは、Objective-Cの継承の応用例として、プロトコルの組み込みやカテゴリを使用したメソッドの追加について、具体的なサンプルコードとともに解説します。

○サンプルコード5:プロトコルを組み込んだ継承

Objective-Cにおけるプロトコルは、特定のメソッドの実装を約束するものです。

これを継承と組み合わせることで、特定のクラスが必ず特定のメソッドを持つことを保証できます。

このコードでは、Printableというプロトコルを定義し、Personクラスがこのプロトコルを実装する例を表しています。

この例では、Personクラスが必ずprintInfoメソッドを実装することが保証されます。

@protocol Printable
- (void)printInfo;
@end

@interface Person : NSObject <Printable>
@property NSString *name;
@property NSInteger age;
@end

@implementation Person
- (void)printInfo {
    NSLog(@"Name: %@, Age: %ld", self.name, (long)self.age);
}
@end

このコードを利用することで、Personオブジェクトを作成し、printInfoメソッドを呼び出すと、指定された情報がログとして出力されることが期待されます。

例えば、次のように使用することができます。

Person *person = [[Person alloc] init];
person.name = @"Taro";
person.age = 25;
[person printInfo];

上記のコードを実行すると、”Name: Taro, Age: 25″というメッセージがログに表示されるでしょう。

○サンプルコード6:カテゴリを用いたメソッドの追加

Objective-Cのカテゴリは、既存のクラスにメソッドを追加する機能です。

これにより、継承を使用せずともクラスの機能を拡張することができます。

このコードでは、NSStringクラスにisNotEmptyという新しいメソッドを追加する例を表しています。

この例では、文字列が空でないかどうかをチェックする機能を持ったメソッドを追加しています。

@interface NSString (IsNotEmpty)
- (BOOL)isNotEmpty;
@end

@implementation NSString (IsNotEmpty)
- (BOOL)isNotEmpty {
    return ![self isEqualToString:@""];
}
@end

このカテゴリを利用することで、NSStringオブジェクトに対してisNotEmptyメソッドを呼び出すことができるようになります。

例えば、次のように使用することができます。

NSString *emptyString = @"";
NSString *nonEmptyString = @"Hello";
NSLog(@"Is emptyString not empty? %d", [emptyString isNotEmpty]);
NSLog(@"Is nonEmptyString not empty? %d", [nonEmptyString isNotEmpty]);

上記のコードを実行すると、次のような結果がログに表示されるでしょう。

"Is emptyString not empty? 0"
"Is nonEmptyString not empty? 1"

これにより、文字列が空でないかどうか簡単にチェックすることが可能となります。

○サンプルコード7:継承を利用したカスタムUIコンポーネントの作成

継承は、既存のクラスの機能を新しいクラスに引き継ぐ技法として広く用いられています。

特にObjective-Cでは、UIKitなどのライブラリクラスを継承してカスタムUIコンポーネントを作成することが一般的です。

このコードでは、UIButtonクラスを継承して、カスタムなボタンを作成するコードを表しています。

この例では、ボタンの背景色やテキストの色をカスタマイズしています。

// カスタムボタンのヘッダファイル
@interface CustomButton : UIButton

@end

// カスタムボタンの実装ファイル
@implementation CustomButton

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // 背景色を青に設定
        self.backgroundColor = [UIColor blueColor];
        // テキストの色を白に設定
        [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    }
    return self;
}

@end

上記のコードを使用することで、青い背景に白いテキストのボタンが作成されます。

このカスタムボタンを使用すれば、アプリケーションのデザインを一貫して保つことができ、デザインの変更や追加も容易になります。

○サンプルコード8:継承を活用したデータの管理

Objective-Cでのデータの管理は、継承を活用して、効率的かつ簡潔に行うことができます。

特に、データモデルの共通の機能やプロパティを基底クラスに持たせ、継承することで、繰り返しのコードを減らすことができます。

このコードでは、動物のデータを管理する基底クラスと、それを継承する犬と猫のクラスを作成するコードを表しています。

この例では、動物の共通のプロパティやメソッドを基底クラスに定義し、犬や猫の特有の機能をそれぞれのクラスで追加しています。

// 動物クラスのヘッダファイル
@interface Animal : NSObject

@property (nonatomic, strong) NSString *name;

- (void)eat;

@end

// 犬クラスのヘッダファイル
@interface Dog : Animal

- (void)bark;

@end

// 猫クラスのヘッダファイル
@interface Cat : Animal

- (void)meow;

@end

このようにして、継承を活用することで、データの管理を効率的に行うことができます。

犬や猫のインスタンスを作成して、それぞれのメソッドを呼び出すと、それぞれの動物の特有の行動や、共通の行動を実行することができます。

○サンプルコード9:例外処理を組み込んだ継承の実装

Objective-Cにおいて例外処理を行う際、NSExceptionクラスを使用します。

このクラスは例外を表現するための基底クラスとして用意されており、それを継承して独自の例外を作成することができます。

ここでは、継承を用いて独自の例外クラスを作成し、それを例外処理に取り入れる方法を説明します。

#import <Foundation/Foundation.h>

// 独自の例外クラスを作成するため、NSExceptionを継承
@interface MyCustomException : NSException
@end

@implementation MyCustomException
@end

int main() {
    @try {
        // 例外をスロー
        [MyCustomException raise:@"MyCustomException" format:@"これは独自の例外です"];
    } @catch (MyCustomException *exception) {
        NSLog(@"独自の例外が捕捉されました:%@", exception.reason);
    } @finally {
        NSLog(@"例外処理が完了しました。");
    }
    return 0;
}

このコードでは、まずMyCustomExceptionという独自の例外クラスを作成しています。

そして、main関数内で@tryブロックの中でこの例外を発生させ、@catchブロックでそれをキャッチしています。

@finallyブロックは、例外が発生してもしなくても必ず実行される部分で、ここでは例外処理が完了したことをログに出力しています。

このコードを実行すると、次のような出力が得られます。

独自の例外が捕捉されました:これは独自の例外です
例外処理が完了しました。

○サンプルコード10:複数のインターフェイスを継承する方法

Objective-Cにおいて、Javaのようにクラスが複数のクラスを継承することはできません。

しかし、インターフェイス(Objective-Cではプロトコルと呼ばれる)を複数継承することは可能です。

ここでは、複数のインターフェイスを継承する方法を紹介します。

まず、2つの異なるプロトコルを定義します。

#import <Foundation/Foundation.h>

@protocol ProtocolA
- (void)methodA;
@end

@protocol ProtocolB
- (void)methodB;
@end

次に、これらのプロトコルを継承するクラスを作成します。

@interface MyClass : NSObject <ProtocolA, ProtocolB>
@end

@implementation MyClass
- (void)methodA {
    NSLog(@"methodAが実行されました。");
}

- (void)methodB {
    NSLog(@"methodBが実行されました。");
}
@end

int main() {
    MyClass *obj = [[MyClass alloc] init];
    [obj methodA];
    [obj methodB];
    return 0;
}

このコードでは、MyClassというクラスがProtocolAProtocolBの2つのプロトコルを継承しています。

そして、それぞれのプロトコルで宣言されているメソッドmethodAmethodBを実装しています。

このコードを実行すると、次のような出力が得られます。

methodAが実行されました。
methodBが実行されました。

●Objective-Cの継承における注意点と対処法

Objective-Cの継承は非常に便利な機能の一つですが、正しく理解しないと予期しないバグやエラーを引き起こす可能性があります。

特に初心者の方々がつまづきやすい点や、経験豊富な開発者であっても注意が必要な点がいくつか存在します。

ここでは、Objective-Cの継承における代表的な注意点と、それらを回避または解決するための対処法について詳しく解説していきます。

○循環参照の問題とその解決方法

循環参照は、継承関係が複雑になると発生しやすい問題の一つです。

具体的には、クラスAがクラスBを継承し、同時にクラスBがクラスAを継承するというような状況が生じると、循環参照が発生してしまいます。

このような状態が続くと、メモリリークやアプリのクラッシュを引き起こすリスクが高まります。

このコードでは循環参照の問題を表しています。

この例ではクラスAがクラスBを継承し、クラスBがクラスAを継承しています。

@interface ClassA : ClassB
@end

@interface ClassB : ClassA
@end

このような循環参照を回避するための基本的な方法は、継承関係をシンプルに保つことです。

具体的には、一つのクラスが別のクラスを継承する際、その継承先のクラスが再び最初のクラスを継承しないように設計する必要があります。

また、継承関係の設計を行う際には、クラス間の関係図を作成することで、循環参照のリスクを可視化することが可能です。

○継承の深さに関する注意点

継承の深さ、すなわち、継承チェーンが長くなりすぎることも注意が必要なポイントです。

継承チェーンが長くなると、コードの読み手が継承関係を追うのが難しくなります。

また、多重継承によって引き起こされる不具合の原因の特定も難しくなる可能性があります。

下記のコードでは、継承の深さが増している例を表しています。

この例では、ClassAを基本として、ClassB、ClassC、ClassDと続けて継承しています。

@interface ClassA
@end

@interface ClassB : ClassA
@end

@interface ClassC : ClassB
@end

@interface ClassD : ClassC
@end

このような深い継承を避けるためには、継承よりもコンポジション(組み合わせ)を積極的に活用することを検討すると良いでしょう。

コンポジションを用いることで、各クラスの役割を明確にし、柔軟なコード設計が可能になります。

継承の深さに関する注意点としては、継承チェーンをシンプルに保つこと、そして継承を過度に使用しないように心掛けることが重要です。

継承は非常に便利な機能ではありますが、適切に使用しないとコードの可読性や保守性を損なう原因となる可能性があります。

●Objective-Cの継承のカスタマイズ方法

Objective-Cを学ぶ際、継承はオブジェクト指向プログラミングの基本となる概念の一つです。

そして、継承を使いこなすことで、多くの強力なカスタマイズが可能となります。

ここでは、Objective-Cの継承におけるカスタマイズ方法について、サンプルコードを交えながら詳しく説明します。

○カスタムプロパティやメソッドを追加する方法

Objective-Cの継承を利用すると、子クラスに新しいプロパティやメソッドを追加することが可能となります。

これによって、親クラスの機能を拡張し、より特化した子クラスを作成することができます。

ここで、動物を表す基本的なクラスとしてAnimalクラスを考えます。

このクラスはシンプルなプロパティとメソッドを持っています。

そして、犬を表すDogクラスをAnimalクラスから継承し、新しいプロパティやメソッドを追加してみましょう。

// Animalクラスの定義
@interface Animal : NSObject
@property NSString *name;
- (void)eat;
@end

@implementation Animal
- (void)eat {
    NSLog(@"%@ は食事をします。", self.name);
}
@end

// Dogクラスの定義 - Animalクラスを継承
@interface Dog : Animal
@property NSString *breed;
- (void)bark;
@end

@implementation Dog
- (void)bark {
    NSLog(@"%@ はワンワンと吠える!", self.name);
}
@end

このコードでは、Animalクラスを基にしてDogクラスを作成しています。

この例では、犬の品種を表すbreedプロパティと、吠える動作を表すbarkメソッドをDogクラスに追加しています。

次に、実際にDogクラスのインスタンスを作成して、新しく追加したプロパティとメソッドを利用してみます。

Dog *myDog = [[Dog alloc] init];
myDog.name = @"ポチ";
myDog.breed = @"シェルティー";
[myDog eat];
[myDog bark];

このコードを実行すると、次のような結果が得られます。

ポチ は食事をします。
ポチ はワンワンと吠える!

まとめ

Objective-Cの継承は、オブジェクト指向プログラミングの核心的な概念として、プログラミングの効率化やコードの再利用性を高めるための強力なツールとなります。

このガイドでは、継承の基本的な使い方から、カスタマイズ方法までを詳細に解説しました。

特にカスタマイズ方法では、親クラスの機能を拡張し、新しいプロパティやメソッドを追加することで、更に柔軟なコードの実装が可能となります。

これらの知識を活かして、Objective-Cの継承を効果的に使用し、品質の高いアプリケーション開発を進めていきましょう。