Objective-Cの__kindofの詳細解説!10選の実践的サンプルコード

Objective-Cの__kindofを使ったコードのイラストObjctive-C
この記事は約26分で読めます。

 

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

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

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

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

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

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

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

はじめに

Objective-CはAppleのiOSやMacOS向けのアプリケーションを開発するためのプログラミング言語として多くの開発者に知られています。

特有の文法や概念を持ち、C言語やSmalltalkの影響を受けたオブジェクト指向言語であり、CやC++と互換性を持ちます。

Objective-Cには多くの特色がありますが、その中でも__kindofというキーワードは非常に便利な機能です。

この記事では、Objective-Cの__kindofキーワードに関して初心者から上級者まで詳しく解説します。

わかりやすいサンプルコード10選を通じて、その魅力と応用方法を徹底的に学べる内容となっています。

●Objective-Cと__kindofの基本

Objective-CはAppleのiOSやMacOS向けのアプリケーションを開発するためのプログラミング言語です。

この言語は、1980年代にBrad CoxとTom Loveによって開発され、その後AppleがNeXTを買収したことをきっかけに、iOSやMacOSの主要な開発言語として広く普及しました。

Objective-Cは、C言語にオブジェクト指向の概念を加えた言語で、C言語の全ての機能に加えて、Smalltalkスタイルのメッセージパッシング機能を有しています。

Objective-Cの特徴は、その動的な性質にあります。

オブジェクト間のメッセージパッシングはランタイムに解決されるため、非常に柔軟なプログラミングが可能です。

また、Objective-CはC++やその他のC系言語と比較して、独特の文法を持っています。

例えば、メソッドの呼び出しはブラケット記法を用いて行い、メッセージパッシングという形でオブジェクト間のコミュニケーションが実現されます。

○Objective-Cの概要

Objective-Cの基本は、C言語の構文にオブジェクト指向機能を加えたものです。

クラス宣言、継承、多態性、カプセル化など、オブジェクト指向言語としての機能を充分に備えています。

また、Objective-Cではメッセージパッシングを中心にしたプログラミングが行われ、これは他の多くのオブジェクト指向言語とは一線を画します。

Objective-Cでは、オブジェクトへのメッセージ送信を行う際、ブラケットを使った独特の文法を採用しています。

これは、Smalltalkの影響を受けたもので、プログラムの可読性と書きやすさを両立しています。

さらに、Objective-Cのランタイムは動的に型情報を処理するため、非常に柔軟なコードを書くことが可能です。

Objective-Cにおいては、メモリ管理も重要な概念です。

初期のバージョンでは手動でのリファレンスカウント方式を取っていましたが、後に「Automatic Reference Counting(ARC)」が導入され、メモリ管理が大幅に簡略化されました。

ARCの導入により、開発者はメモリリークやその他のメモリ関連の問題について、以前よりも少ない心配でコーディングに集中できるようになりました。

●__kindofの具体的な使い方

__kindofはObjective-Cにおける型の指定を柔軟にするためのキーワードです。

このキーワードは、特にジェネリクスを使用したコードで役立ち、コンパイラに対して特定のクラスのサブクラスまでを許容することを伝える役割を果たします。

__kindofの主な用途は、戻り値やパラメータの型として使用する場面が多いです。

それでは具体的な使い方を見ていきましょう。

○サンプルコード1:__kindofを用いた基本的な宣言

Objective-Cにおける__kindofの使用は非常にシンプルです。

下記のコードでは、UIViewのサブクラスを返すメソッドを表しています。

- (__kindof UIView *)fetchCustomView {
    // ... 何らかの処理 ...
    return customViewInstance;
}

このコードではfetchCustomViewメソッドを使ってUIViewのサブクラスのインスタンスを返しています。

この例では、__kindofを使用しているため、UIButtonやUILabelのようなUIViewのサブクラスのインスタンスも返すことが可能です。

また、この方法は特定のUIViewサブクラスのみを期待する場合にも利用でき、その場合、キャスティングをせずにサブクラスのメソッドやプロパティを安全に利用できます。

○サンプルコード2:__kindofと型の柔軟性

__kindofは、コンテナクラスの型を柔軟にするのに特に役立ちます。

下記のコードは、NSArrayの中に特定のクラスのインスタンスのみを格納するシナリオを表しています。

NSArray<__kindof UIView *> *customViews;

このコードでは、NSArrayの中にUIViewのサブクラスのインスタンスを格納することを意味しています。

このNSArrayから取得した各オブジェクトは、UIViewのサブクラスとしてのメソッドやプロパティを利用することができます。

例えば、次のようにUIButtonのインスタンスを取得し、そのメソッドを使用することが可能です。

UIButton *button = customViews[0];
[button setTitle:@"Click Me!" forState:UIControlStateNormal];

このように、__kindofを利用することで、NSArrayの中の具体的なクラスのインスタンスにアクセスし、そのメソッドやプロパティを安全に使用することができます。

○サンプルコード3:__kindofを活用したメソッドの定義

Objective-Cにおける__kindofキーワードは、柔軟性を持たせた型の扱いを可能にします。

特にメソッドの戻り値や引数として利用する際に、その有用性を感じることができるでしょう。

ここでは、__kindofを使用してメソッドを定義する方法を解説します。

@interface Animal : NSObject
@end

@interface Dog : Animal
@end

@interface Cat : Animal
@end

@interface Zoo : NSObject
- (__kindof Animal *)fetchRandomAnimal;
@end

このコードでは、Animalという基底クラスと、そのサブクラスであるDogCatを定義しています。

そして、ZooというクラスにはfetchRandomAnimalというメソッドがあります。

このメソッドの戻り値に__kindofキーワードを使用することで、DogCatなどのAnimalのサブクラスのインスタンスを返すことができるようになりました。

この例では、fetchRandomAnimalメソッドを通じて取得した動物が、具体的にどのクラスのインスタンスであるかは分からない状況を想定しています。

しかし、__kindofのおかげで、戻り値をDogやCatのような具体的なサブクラスとして扱うことが可能となりました。

ここでは、このメソッドを利用した実装の一例を紹介します。

@implementation Zoo

- (__kindof Animal *)fetchRandomAnimal {
    NSArray *animals = @[ [Dog new], [Cat new] ];
    NSInteger randomIndex = arc4random_uniform((unsigned int)animals.count);
    return animals[randomIndex];
}

@end

こちらの実装では、犬と猫のインスタンスを配列に格納し、ランダムに1つ選んで返しています。

このコードを使用すると、fetchRandomAnimalメソッドを通じてランダムにDogまたはCatのインスタンスを取得することができます。

これにより、取得した動物が犬か猫かを確認する処理を簡単に実装することが可能となります。

○サンプルコード4:__kindofとジェネリクスの組み合わせ

Objective-Cにおけるジェネリクスは、型の柔軟性をさらに拡張することができる機能です。

__kindofと組み合わせることで、より高度な型の柔軟性を実現することができます。

下記のサンプルコードでは、__kindofとジェネリクスを組み合わせて、特定のクラスのサブクラスのインスタンスを格納するNSArrayを定義しています。

@interface AnimalArray<ObjectType: Animal *> : NSArray<ObjectType>
- (void)addAnimal:(__kindof Animal *)animal;
@end

このコードでは、AnimalArrayというNSArrayのサブクラスを定義しています。

このクラスは、ジェネリクスを用いてAnimalのサブクラスのインスタンスを要素として持つことができる配列を定義しています。

また、addAnimal:メソッドでは、__kindofキーワードを使用して、任意のAnimalのサブクラスのインスタンスを引数として受け取ることができます。

このように、__kindofとジェネリクスを組み合わせることで、より具体的な型の制約を持ったコレクションクラスを作成することができます。

●__kindofの応用例

Objective-Cにおいて、__kindofキーワードは特に型の柔軟性とポリモーフィズムの面で非常に便利なものとして知られています。

ここからは、具体的な応用例として、__kindofを活用したコードのサンプルと、それらの詳しい解説を行っていきます。

○サンプルコード5:__kindofを使った配列の操作

Objective-Cにおける配列の操作は、多くの場面で使用されます。

ここでは、__kindofを使って、配列内の特定のクラスのオブジェクトを操作するシンプルな例を見てみましょう。

@interface MyArray : NSObject
- (void)addObject:(__kindof NSObject *)object;
- (__kindof NSObject *)objectAtIndex:(NSUInteger)index;
@end

@implementation MyArray {
    NSMutableArray *__array;
}
- (instancetype)init {
    if (self = [super init]) {
        __array = [NSMutableArray array];
    }
    return self;
}

- (void)addObject:(__kindof NSObject *)object {
    [__array addObject:object];
}

- (__kindof NSObject *)objectAtIndex:(NSUInteger)index {
    return [__array objectAtIndex:index];
}
@end

このコードでは、MyArrayというクラスを作成しています。

この例では、__kindofキーワードを使って、任意のNSObjectサブクラスのオブジェクトを追加し、取得するメソッドを持っています。

このように__kindofを使用することで、特定のサブクラスに限定せずに、様々なオブジェクトを柔軟に扱うことが可能となります。

このコードを利用して、例えばNSStringやNSNumberのオブジェクトを同じ配列に格納し、取り出すことができます。

具体的な動作は次の通りです。

MyArray *array = [[MyArray alloc] init];
[array addObject:@"文字列"];
[array addObject:@(123)];

NSString *stringObj = [array objectAtIndex:0];
NSNumber *numberObj = [array objectAtIndex:1];

NSLog(@"文字列オブジェクト: %@", stringObj);
NSLog(@"数値オブジェクト: %@", numberObj);

上記のコードを実行すると、文字列オブジェクトと数値オブジェクトがそれぞれ取り出され、ログに出力されることが確認できます。

○サンプルコード6:__kindofでのポリモーフィズムの実現

Objective-Cにおけるポリモーフィズムは、異なるクラスのオブジェクトが同一のインターフェイスを持つことを指します。

__kindofを利用することで、このポリモーフィズムをより簡単に実現することができます。

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

@interface Dog : Animal
@end

@interface Cat : Animal
@end

@implementation Animal
- (void)speak {
    NSLog(@"動物の音");
}
@end

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

@implementation Cat
- (void)speak {
    NSLog(@"ニャー");
}
@end

@interface Zoo : NSObject
- (void)addAnimal:(__kindof Animal *)animal;
- (void)letAllAnimalsSpeak;
@end

@implementation Zoo {
    NSMutableArray *__animals;
}
- (instancetype)init {
    if (self = [super init]) {
        __animals = [NSMutableArray array];
    }
    return self;
}

- (void)addAnimal:(__kindof Animal *)animal {
    [__animals addObject:animal];
}

- (void)letAllAnimalsSpeak {
    for (Animal *animal in __animals) {
        [animal speak];
    }
}
@end

このコードでは、Animalという基本クラスと、そのサブクラスであるDogとCatを定義しています。

そして、Zooクラスを定義し、その中で複数のAnimalオブジェクトを格納し、それぞれにspeakメソッドを呼び出すことで、それぞれの動物の鳴き声を出力する処理を実装しています。

次のようにZooクラスを利用すれば、DogとCatのオブジェクトを同じZooオブジェクトに格納し、それぞれのspeakメソッドを呼び出すことができます。

Zoo *zoo = [[Zoo alloc] init];
[zoo addAnimal:[[Dog alloc] init]];
[zoo addAnimal:[[Cat alloc] init]];

[zoo letAllAnimalsSpeak];

上記のコードを実行すると、「ワンワン」と「ニャー」というログが出力されます。

これにより、__kindofを使ってポリモーフィズムを簡単に実現することができることがわかります。

○サンプルコード7:__kindofを活用したUI部品の管理

Objective-CにおけるUI部品の管理では、多くのUI部品が異なるクラスに属しています。

しかし、それらの部品を一括で管理したいとき、__kindofを使用することで型の柔軟性を持たせ、効率的な管理が可能となります。

このコードでは__kindofを使用してUIViewのサブクラスを柔軟に扱う例を表しています。

この例では、UIViewのサブクラスとしてUILabelやUIButtonなどの部品を含む配列を作成し、それを取得する際に__kindofを活用しています。

#import <UIKit/UIKit.h>

@interface UIComponentsManager : NSObject

- (void)addComponent:(__kindof UIView *)component;
- (nullable __kindof UIView *)getComponentAtIndex:(NSInteger)index;

@end

@implementation UIComponentsManager {
    NSMutableArray *__components;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        __components = [NSMutableArray array];
    }
    return self;
}

- (void)addComponent:(__kindof UIView *)component {
    [__components addObject:component];
}

- (nullable __kindof UIView *)getComponentAtIndex:(NSInteger)index {
    if (index < 0 || index >= __components.count) {
        return nil;
    }
    return __components[index];
}

@end

こちらのコードでのポイントは、addComponent:メソッドとgetComponentAtIndex:メソッドで__kindofを使用していることです。

これにより、UIViewのサブクラスを柔軟に取り扱えるようになります。

具体的にはUILabelやUIButtonなどの異なるUI部品を同じ配列で管理しながら、それを取得する際にも適切な型として取り扱うことができます。

このコードを利用すると、UIComponentsManagerのインスタンスを作成し、UILabelとUIButtonをaddComponentメソッドを使って追加します。

その後、getComponentAtIndexメソッドで指定したインデックスのUI部品を取得できます。

取得したUI部品は、そのままUILabelやUIButtonとして利用することができます。

○サンプルコード8:__kindofを使ったエラーハンドリング

Objective-Cでのエラーハンドリングには様々な方法がありますが、エラーの型が異なる場合に一括で扱いたいとき、__kindofを使用することで柔軟にエラーを取り扱うことが可能となります。

このコードでは__kindofを使用してNSErrorのサブクラスを柔軟に扱う例を表しています。

この例では、NSErrorのサブクラスとしてカスタムエラークラスを定義し、それを__kindofを使って取り扱います。

#import <Foundation/Foundation.h>

@interface CustomError : NSError

@property (nonatomic, readonly) NSString *additionalInfo;

- (instancetype)initWithUserInfo:(NSDictionary *)userInfo additionalInfo:(NSString *)info;

@end

@implementation CustomError

- (instancetype)initWithUserInfo:(NSDictionary *)userInfo additionalInfo:(NSString *)info {
    self = [super initWithDomain:@"com.example.customerror" code:1000 userInfo:userInfo];
    if (self) {
        _additionalInfo = info;
    }
    return self;
}

@end

@interface ErrorHandler : NSObject

- (void)handleError:(__kindof NSError *)error;

@end

@implementation ErrorHandler

- (void)handleError:(__kindof NSError *)error {
    if ([error isKindOfClass:[CustomError class]]) {
        CustomError *customError = (CustomError *)error;
        NSLog(@"Handling custom error with additional info: %@", customError.additionalInfo);
    } else {
        NSLog(@"Handling generic error: %@", error.localizedDescription);
    }
}

@end

このコードのポイントは、handleError:メソッドでの__kindofの使用です。

これにより、NSErrorのサブクラスを柔軟に取り扱えるようになります。

具体的にはCustomErrorクラスをhandleErrorメソッドに渡すことで、そのエラーがCustomErrorの場合とそれ以外の場合で異なる処理を行うことができます。

このコードを利用すると、ErrorHandlerのインスタンスを作成し、handleErrorメソッドにエラーを渡します。

渡されたエラーがCustomErrorの場合、そのエラーのadditionalInfoプロパティを出力します。

それ以外のエラーの場合、標準のエラーメッセージを出力します。

○サンプルコード9:__kindofを使ったキャスティングの最適化

Objective-Cでは、型キャスティングは一般的な操作としてよく用いられます。

しかし、これを行う際に型安全性を維持することが難しくなることがあります。

__kindofを使うと、この問題を一部解消できます。

このコードでは__kindofを使って型キャスティングを行う方法を表しています。

この例では、UIViewのサブクラスを__kindofを使って効果的にキャスティングしています。

#import <UIKit/UIKit.h>

@interface CustomView : UIView
- (void)customMethod;
@end

@implementation CustomView
- (void)customMethod {
    NSLog(@"This is a custom method in CustomView");
}
@end

UIView *__kindof createView(BOOL isCustom) {
    if (isCustom) {
        return [[CustomView alloc] init];
    }
    return [[UIView alloc] init];
}

int main() {
    UIView *view = createView(YES);
    if ([view isKindOfClass:[CustomView class]]) {
        [(CustomView *)view customMethod];  // キャスティングが必要
    }
    return 0;
}

上記のコードを実行すると、「This is a custom method in CustomView」というメッセージがログに表示されます。

これは、createView関数がCustomViewインスタンスを返し、それが正しくキャスティングされてcustomMethodが呼び出されるからです。

__kindofを用いることで、関数やメソッドが返すオブジェクトの具体的なサブタイプを隠蔽することができ、その結果としてキャスティングがスムーズに行われるようになります。

○サンプルコード10:__kindofとプロトコルの組み合わせ

プロトコルは、Objective-Cでインターフェースを定義するための仕組みです。

__kindofと組み合わせることで、より柔軟なコードの実装が可能になります。

このコードでは__kindofとプロトコルを組み合わせる方法を表しています。

この例では、特定のプロトコルを採用したクラスのインスタンスを返すメソッドを定義しています。

#import <Foundation/Foundation.h>

@protocol MyProtocol <NSObject>
- (void)protocolMethod;
@end

@interface MyClass : NSObject <MyProtocol>
@end

@implementation MyClass
- (void)protocolMethod {
    NSLog(@"This is protocolMethod in MyClass");
}
@end

- (id<MyProtocol> __kindof)createInstance {
    return [[MyClass alloc] init];
}

int main() {
    id<MyProtocol> obj = createInstance();
    [obj protocolMethod];
    return 0;
}

上記のコードを実行すると、「This is protocolMethod in MyClass」というメッセージがログに表示されます。

createInstanceメソッドは、MyProtocolを採用したクラスのインスタンスを返しますが、__kindofを使用することで、具体的なクラスの型を隠蔽することができます。

●注意点と対処法

Objective-Cの__kindofは、多くの状況で非常に便利ですが、正しく使わないと予期しない動作やエラーの原因となり得ます。

ここでは、__kindofを使用する際の注意点と、それらの問題を回避するための対処法を詳しく解説していきます。

○__kindofの誤用に関する警告

__kindofは、型の柔軟性を提供するためにObjective-Cに導入されました。

しかし、その柔軟性は適切に使われないと、バグの原因となることもあります。

例えば、次のコードを考えてみましょう。

NSArray<__kindof UIView *> *views = @[button, label];
UIButton *button = views[0];
UILabel *label = views[1];

この例では、配列viewsUIButtonUILabelのインスタンスを格納しています。

__kindofのおかげで、UIButton *buttonUILabel *labelとして取り出すことができます。

しかし、インデックスを間違えると、次のようになります。

UIButton *button = views[1]; // 実際にはUILabelのインスタンス
UILabel *label = views[0];   // 実際にはUIButtonのインスタンス

この場合、コンパイル時にはエラーは発生しないものの、実行時には不適切なキャスティングが発生し、アプリケーションはクラッシュします。

このような問題を回避するためには、__kindofを使用する際に、配列やコレクションの中身を明確に知っている必要があります。

また、可能な限り具体的な型を指定することで、このような問題を避けることができます。

○__kindofと他のキーワードとの競合

__kindofは他のObjective-Cのキーワードや機能と一緒に使われることがあります。例えば、プロトコルとの組み合わせなど。

しかし、誤って使用すると、意図しない動作を引き起こす可能性があります。

例として、次のコードを見てみましょう。

NSArray<__kindof id<SomeProtocol>> *objects = @[obj1, obj2];

この例では、SomeProtocolを実装する任意のオブジェクトを配列objectsに格納しています。

__kindofid<SomeProtocol>を組み合わせることで、型の柔軟性とプロトコルの制約を同時に活用しています。

しかし、このような組み合わせを誤って使うと、期待する動作とは異なる結果をもたらすことがあります。

特に、複数のプロトコルやジェネリクスを併用する際には注意が必要です。

これらの問題を回避するためには、__kindofと他のキーワードや機能を組み合わせる際には、それぞれの動作を正確に理解しておくことが必要です。

また、コードのリファクタリングや変更を行う際にも、__kindofの使用箇所を特に注意深く確認することが推奨されます。

●カスタマイズ方法

Objective-Cのプログラムを書く際、__kindofキーワードは非常に便利なツールの一つです。

その柔軟性と実用性を高めるためのカスタマイズ方法について、実際のサンプルコードを交えながら詳しく解説していきます。

○__kindofのカスタム拡張方法

Objective-Cにおける__kindofのキーワードは、型の柔軟性を提供するためのものですが、それをカスタム拡張する方法も存在します。

ここでは、その一例として、カスタム拡張の方法を紹介します。

@interface Container<ObjectType> : NSObject
- (void)addObject:(__kindof ObjectType)object;
- (id)customExtensionMethod;
@end

このコードでは、ContainerクラスにObjectTypeというジェネリック型を使用しています。

そして、addObject:メソッドの引数には__kindof ObjectTypeと宣言して、このメソッドを通じて、ObjectTypeのサブクラスのインスタンスも渡せるようにしています。

また、customExtensionMethodという新しいメソッドを定義して、カスタム拡張の一例を表しています。

この例では、Containerクラスをジェネリック型でカスタマイズし、更に__kindofキーワードを使ってその柔軟性を強化しています。

このコードを実際に実行すると、Containerクラスは指定されたジェネリック型ObjectTypeのインスタンスやそのサブクラスのインスタンスを格納できるようになります。

また、customExtensionMethodメソッドを利用することで、独自の拡張を行うことができます。

○__kindofと関連するオプションの設定

__kindofキーワードのみならず、Objective-Cには__kindofと相互作用するさまざまなオプションや設定が存在します。

ここでは、それらの一部を紹介し、サンプルコードを交えて詳しく解説します。

@interface CustomView : UIView
@property (nonatomic, strong) __kindof UIButton *customButton;
@end

このコードでは、CustomViewクラスにcustomButtonプロパティを追加しています。

このプロパティの型は__kindof UIButton *となっており、UIButtonのサブクラスのインスタンスもこのプロパティに代入できるようになっています。

この例では、__kindofキーワードを使って、プロパティの型に柔軟性を持たせています。

このコードを実行すると、CustomViewクラスのインスタンスは、customButtonプロパティに、UIButtonのインスタンスだけでなく、そのサブクラスのインスタンスも代入できるようになります。

これにより、カスタムボタンや特定のスタイルを持ったボタンなど、UIButtonのサブクラスを使用したい場合にも対応できるようになります。

まとめ

Objective-Cの__kindofキーワードは、型の柔軟性を高めるためのものです。

このキーワードを使用することで、指定した型やそのサブクラスのインスタンスを扱うことができ、プログラムの拡張性や再利用性を向上させることができます。

この記事を通じて、__kindofキーワードの基本的な使い方や応用例、カスタマイズ方法などを学び、Objective-Cのプログラムをより効果的に書く手助けとなることを期待しています。