Objective-Cのオーバーライド完全解説!たった8つのサンプルコードでマスター

Objective-Cでのオーバーライドの完全解説イメージObjctive-C
この記事は約18分で読めます。

 

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

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

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

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

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

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

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

はじめに

Objective-Cの世界には、多くのプログラマーが利用する基本的な機能やテクニックがあります。

その中でも「オーバーライド」という技術は、特にオブジェクト指向プログラミングを行う上で避けては通れない道といえるでしょう。

本記事では、Objective-Cでのオーバーライドの基本から応用、さらには注意点まで詳しく解説していきます。

そして、オーバーライドの実際の使用例をサンプルコードとして8つ提供し、それぞれのコードの特徴や実行結果を交えながら解説していきます。

●Objective-Cとは

Objective-Cは、C言語の上にオブジェクト指向の機能を追加したプログラミング言語です。

AppleのiOSやmacOSなどのOSでのアプリケーション開発に使われてきた歴史があります。

Objective-Cの特長としては、メッセージベースの動的なメソッド呼び出しや、カテゴリという拡張機能、そして強力なランタイムが挙げられます。

○Objective-Cの基本概念

Objective-Cにおけるプログラムは、主に「クラス」と「オブジェクト」によって構成されます。

クラスはオブジェクトの設計図のようなもので、そのクラスから具体的なインスタンスであるオブジェクトが作成されます。

このオブジェクトは、クラスに定義された「メソッド」を持っており、これによって各種の動作を実行します。

また、オブジェクトは「プロパティ」というデータを持ち、これによってそのオブジェクトの状態が保持されます。

○Objective-Cの歴史と特徴

Objective-Cは、1980年代にStepstone社によって開発されました。

その後、NeXT社がこの言語を採用し、NeXTのオペレーティングシステムであるNeXTSTEPの開発に使用しました。

そして、AppleがNeXT社を買収したことによって、Objective-CはAppleの主要なプログラミング言語として位置づけられるようになりました。

Objective-Cの最も大きな特徴は、C言語の基本的な文法を継承しつつ、Smalltalkからの影響を受けた動的なオブジェクト指向の機能を持っている点です。

この動的な特性は、ランタイムにおけるメソッドの探索や呼び出し、さらにはメソッドの置き換えなど、高度なプログラミング技術を可能にしています。

一方で、近年はAppleが開発したSwiftというプログラミング言語がiOSやmacOSの開発言語として推奨されるようになってきました。

しかし、Objective-Cで書かれた既存のライブラリやフレームワークが多数存在するため、現在もObjective-Cの知識は非常に価値があります。

●オーバーライドとは

オーバーライドは、プログラミングの中で非常に重要な概念の一つです。

特にオブジェクト指向プログラミングにおいては、この概念を理解していないと、上級者としてのスキルを磨くことが難しいでしょう。

Objective-Cもオブジェクト指向の言語であり、オーバーライドはその中核的な概念として位置づけられています。

○オーバーライドの定義

オーバーライドは、子クラスが親クラスのメソッドを再定義することを指します。

これにより、同じメソッド名でも、子クラスに合わせて異なる動作や処理を行うことができます。

例えば、親クラスにshowMessageというメソッドがあり、”Hello!”というメッセージを表示するとします。

子クラスでは、このメッセージを”Hello from Child class!”と表示したい場合、showMessageメソッドをオーバーライドしてそのように変更することができます。

@interface ParentClass : NSObject
- (void)showMessage;
@end

@implementation ParentClass
- (void)showMessage {
    NSLog(@"Hello!");
}
@end

@interface ChildClass : ParentClass
@end

@implementation ChildClass
- (void)showMessage {
    NSLog(@"Hello from Child class!");
}
@end

このコードでは、ParentClassという親クラスと、その子クラスであるChildClassを定義しています。

親クラスのshowMessageメソッドは”Hello!”を表示しますが、子クラスではこのメソッドをオーバーライドして”Hello from Child class!”と表示するようにしています。

○オーバーライドの必要性とその利点

オーバーライドの最大の利点は、コードの再利用性を高めることです。

親クラスのメソッドをそのまま利用するのではなく、必要に応じて子クラスで変更や追加を行うことができます。

これにより、同じ基本的な動作を持つ複数のクラスを効率よく実装することができます。

また、オーバーライドを活用することで、特定の子クラスのみで特有の動作や処理を実装することも可能です。

これにより、クラスの汎用性を保ちつつ、特定の状況や条件に応じて異なる動作を実現することができます。

●Objective-Cでのオーバーライドの基本

Objective-Cは多くのプログラミング言語と同じく、オブジェクト指向の概念を持っています。

オブジェクト指向の中でも、特にオーバーライドは非常に重要な概念となっています。

ここでは、Objective-Cでのオーバーライドの基本について、詳細な説明とサンプルコードを交えながらご紹介します。

○オーバーライドの基本構文

オーバーライドとは、子クラスが親クラスのメソッドを上書きすることを指します。

Objective-Cでのオーバーライドは、親クラスで定義されたメソッドと同じメソッド名、引数、返り値を持ったメソッドを子クラスで再定義することで実現します。

// 親クラス
@interface ParentClass : NSObject

- (void)displayMessage;

@end

@implementation ParentClass

- (void)displayMessage {
    NSLog(@"これは親クラスのメッセージです。");
}

@end

// 子クラス
@interface ChildClass : ParentClass

@end

@implementation ChildClass

- (void)displayMessage {
    NSLog(@"これは子クラスでオーバーライドされたメッセージです。");
}

@end

このコードでは、親クラスParentClassとその子クラスChildClassを定義しています。

親クラスにはdisplayMessageというメソッドが定義されており、子クラスではこのメソッドをオーバーライドしています。

子クラスのインスタンスを作成し、displayMessageメソッドを呼び出すと、子クラスでオーバーライドされたメソッドが実行されます。

この例では、実行すると「これは子クラスでオーバーライドされたメッセージです。」というメッセージが表示されることになります。

○オーバーライドの使用シーン

オーバーライドは多様なシーンで利用されます。例えば、親クラスで定義されたメソッドの振る舞いを、子クラスごとに異なるものにしたい場合や、親クラスで定義されたメソッドに新しい機能を追加したい場合などに利用されます。

●オーバーライドの詳細な使い方

オーバーライドは、継承関係にある親クラスのメソッドを子クラスで新たに定義し直すことを指します。

Objective-Cにおけるオーバーライドの詳細な使い方を、サンプルコードを交えて解説していきます。

○サンプルコード1:基本的なオーバーライドの例

このコードでは基本的なオーバーライドの方法を表しています。

この例では親クラスのメソッドを子クラスでオーバーライドしています。

@interface ParentClass : NSObject
- (void)showMessage;
@end

@implementation ParentClass
- (void)showMessage {
    NSLog(@"This is ParentClass method.");
}
@end

@interface ChildClass : ParentClass
- (void)showMessage;
@end

@implementation ChildClass
- (void)showMessage {
    NSLog(@"This is ChildClass method.");
}
@end

ChildClass *child = [[ChildClass alloc] init];
[child showMessage];

上記のサンプルコードを実行すると、「This is ChildClass method.」と表示されます。

これは、ChildClassParentClassshowMessageメソッドをオーバーライドしたためです。

○サンプルコード2:親クラスのメソッドを呼び出すオーバーライド

オーバーライドしたメソッド内で、親クラスのメソッドを呼び出す場合の例を紹介します。

この例では、オーバーライドしても親クラスのメソッドを継承して利用しています。

@implementation ChildClass
- (void)showMessage {
    [super showMessage];
    NSLog(@"This is ChildClass additional message.");
}
@end

ChildClass *child = [[ChildClass alloc] init];
[child showMessage];

上記のサンプルコードを実行すると、「This is ParentClass method.」「This is ChildClass additional message.」の2つのメッセージが表示されます。

○サンプルコード3:複数のメソッドをオーバーライドする例

複数のメソッドをオーバーライドする場合の実装方法を表します。

この例では、2つのメソッドを持つ親クラスを継承し、それぞれのメソッドをオーバーライドしています。

@interface ParentClass : NSObject
- (void)firstMessage;
- (void)secondMessage;
@end

@implementation ParentClass
- (void)firstMessage {
    NSLog(@"First message from ParentClass.");
}
- (void)secondMessage {
    NSLog(@"Second message from ParentClass.");
}
@end

@interface ChildClass : ParentClass
- (void)firstMessage;
- (void)secondMessage;
@end

@implementation ChildClass
- (void)firstMessage {
    NSLog(@"First message from ChildClass.");
}
- (void)secondMessage {
    [super secondMessage];
    NSLog(@"Additional message from ChildClass.");
}
@end

ChildClass *child = [[ChildClass alloc] init];
[child firstMessage];
[child secondMessage];

上記のサンプルコードを実行すると、次のメッセージが順に表示されます。

  • First message from ChildClass.
  • Second message from ParentClass.
  • Additional message from ChildClass.

これらのサンプルコードを通して、Objective-Cにおけるオーバーライドの基本的な使用方法を理解することができます。

●オーバーライドの応用例

オーバーライドの基本を理解した上で、さらに深く応用してみると、Objective-Cの真髄に触れることができます。

ここでは、オーバーライドの応用的な使用方法に焦点を当て、3つのサンプルコードを通して詳しく解説していきます。

○サンプルコード4:オーバーライドを活用したカスタムビューの作成

このコードでは、Objective-Cでのカスタムビューを作成するために、オーバーライドを利用しています。

この例では、親クラスのビューを継承し、特定の描画処理を変更して、オリジナルのビューを実装しています。

#import <UIKit/UIKit.h>

@interface CustomView : UIView
@end

@implementation CustomView

// 描画処理をオーバーライド
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];  // 親クラスの描画処理を呼び出す
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetRGBFillColor(context, 1.0, 0, 0, 1.0);  // 赤色で塗りつぶす
    CGContextFillRect(context, rect);
}

@end

このサンプルコードでは、UIViewを継承したCustomViewクラスを作成しています。

drawRect:メソッドをオーバーライドして、親クラスの描画処理を呼び出した後、赤色で塗りつぶす処理を追加しています。

このように、オーバーライドを活用すれば、親クラスの既存のメソッドに追加の処理を加えることが可能となります。

このコードを実行すると、CustomViewクラスのオブジェクトが赤色で塗りつぶされたビューとして表示されるでしょう。

○サンプルコード5:データの変更をトリガーとしてオーバーライドを利用する

オーバーライドを利用すれば、特定のデータが変更されたときに、それをトリガーとして特定の処理を実行することができます。

このコードでは、プロパティの値が変更されたときに、その変更を監視して特定の処理を行います。

#import <Foundation/Foundation.h>

@interface MonitorData : NSObject
@property (nonatomic, strong) NSString *data;
@end

@implementation MonitorData

- (void)setData:(NSString *)data {
    _data = data;
    NSLog(@"データが変更されました: %@", data);
}

@end

このサンプルコードでは、MonitorDataクラス内のdataプロパティをオーバーライドして、データが変更された際に、NSLogを用いてその変更をログに出力しています。

このコードを実行し、dataプロパティの値を変更すると、ログに「データが変更されました」とともに、変更後のデータの値が出力されます。

○サンプルコード6:オーバーライドとプロトコルを組み合わせる応用例

オーバーライドは、プロトコルと組み合わせることで、より高度な実装が可能となります。

このコードでは、プロトコルのメソッドをオーバーライドして、特定の動作をカスタマイズしています。

#import <Foundation/Foundation.h>

@protocol ProtocolExample
- (void)displayMessage;
@end

@interface MyClass : NSObject <ProtocolExample>
@end

@implementation MyClass

- (void)displayMessage {
    NSLog(@"オリジナルのメッセージ");
}

@end

@interface MySubClass : MyClass
@end

@implementation MySubClass

// メソッドをオーバーライド
- (void)displayMessage {
    [super displayMessage];
    NSLog(@"オーバーライドしたメッセージ");
}

@end

このサンプルコードでは、ProtocolExampleというプロトコルを定義し、その中のdisplayMessageメソッドをオーバーライドしています。

継承したMySubClassで、そのメソッドをオーバーライドして、追加のメッセージをログに出力しています。

このコードを実行すると、MySubClassクラスのオブジェクトでdisplayMessageメソッドを呼び出すと、「オリジナルのメッセージ」と「オーバーライドしたメッセージ」が順にログに出力されるでしょう。

●注意点と対処法

Objective-Cでのオーバーライドを扱う際には、多くのメリットがありますが、同時に様々な注意点も存在します。

ここでは、Objective-Cのオーバーライド時によく遭遇する問題や、その対処法について解説いたします。

○オーバーライドの時の共通のミス

オーバーライドを行う際、特に初心者の間でよく見られるミスをいくつか紹介します。

  1. 親クラスのメソッドシグネチャと完全に一致していない。
  2. @superを用いて親クラスのメソッドを呼び出していない。
  3. オーバーライドするメソッドが、実は親クラスに存在しない。

これらのミスを避けるためには、次のような対処法が考えられます。

  1. メソッドのシグネチャが正確であるか、ドキュメントやヘッダーファイルをよく確認しましょう。
  2. 必要に応じて親クラスのメソッドを呼び出すためには、@superを使用しましょう。
  3. オーバーライドしたいメソッドが親クラスに実際に存在するかを、再度確認しましょう。

○オーバーライド時に起こり得るエラーとその対処法

オーバーライド時には、さまざまなエラーが起こり得ます。

ここでは、主なエラーとその対処法について詳しく説明します。

  1. 親クラスに存在しないメソッドをオーバーライドしようとした。

このコードでは、存在しないメソッドをオーバーライドしようとしています。

この例では、someMethodというメソッドが親クラスには存在しないため、エラーが発生します。

@interface ChildClass : ParentClass
- (void)someMethod; // 親クラスにこのメソッドは存在しない
@end

@implementation ChildClass
- (void)someMethod {
    // ...
}
@end

この場合の対処法は、親クラスの実装やヘッダーファイルを確認して、オーバーライドしようとしているメソッド名が正確であるかをチェックすることです。

  1. オーバーライドする際のメソッドのシグネチャが一致していない。

このコードでは、メソッドのシグネチャが一致していないため、オーバーライドとして認識されず、エラーが発生します。

@interface ParentClass : NSObject
- (void)methodWithArg:(int)val;
@end

@interface ChildClass : ParentClass
- (void)methodWithArg:(NSString *)val; // intではなく、NSStringを受け取るメソッドとして定義
@end

この場合の対処法は、親クラスのメソッドのシグネチャを正確に確認し、子クラスでの定義を修正することです。

●オーバーライドのカスタマイズ方法

Objective-Cにおけるオーバーライドは、子クラスで親クラスのメソッドを再定義する際に利用されます。

しかし、単にメソッドを再定義するだけでなく、その動作や属性を柔軟にカスタマイズすることが求められる場面もあります。

ここでは、そのようなカスタマイズ方法に焦点を当て、具体的なサンプルコードを交えながら詳しく解説していきます。

○サンプルコード7:オーバーライドの動作をカスタマイズする方法

このコードでは、親クラスのメソッドをオーバーライドし、特定の条件下で親クラスのメソッドを呼び出すカスタマイズを行っています。

この例では、特定の条件が満たされた場合のみ、親クラスのメソッドを呼び出して、その他の場合はカスタマイズされた動作を実行しています。

// 親クラス
@interface ParentClass : NSObject
- (void)showMessage;
@end

@implementation ParentClass
- (void)showMessage {
    NSLog(@"親クラスのメッセージ");
}
@end

// 子クラス
@interface ChildClass : ParentClass
@end

@implementation ChildClass
- (void)showMessage {
    if (/* 何らかの条件 */) {
        [super showMessage];
    } else {
        NSLog(@"子クラスのカスタマイズされたメッセージ");
    }
}
@end

この例を実行すると、特定の条件が満たされている場合に「親クラスのメッセージ」と表示され、それ以外の場合は「子クラスのカスタマイズされたメッセージ」と表示されることになります。

○サンプルコード8:オーバーライドに関連する属性のカスタマイズ

Objective-Cでは、オーバーライドされたメソッドの属性をカスタマイズするためのいくつかの属性が提供されています。

このコードでは、オーバーライドされたメソッドが非同期に実行されるようにカスタマイズしています。

この例では、async属性を使用して、非同期に実行されるメソッドを表しています。

// 親クラス
@interface ParentClass : NSObject
- (void)fetchData;
@end

@implementation ParentClass
- (void)fetchData {
    // データの取得処理
}
@end

// 子クラス
@interface ChildClass : ParentClass
@end

@implementation ChildClass
- (void)fetchData async {
    // 非同期でのデータ取得処理
}
@end

この例を実行すると、ChildClassfetchDataメソッドは非同期に実行され、データの取得がバックグラウンドで行われることになります。

まとめ

Objective-Cのオーバーライド機能は、ソフトウェア開発の中で非常に重要な役割を果たします。

特に、継承された親クラスのメソッドを子クラスで適切に再定義することで、コードの再利用性を高めるとともに、柔軟なプログラムの実装が可能となります。

本記事では、オーバーライドの基本的な概念から、その応用やカスタマイズ方法に至るまでの詳細な説明を行いました。

これらの知識をもとに、より効率的で品質の高いソフトウェア開発を行うための一助となれば幸いです。