初心者必見!Objective-Cでインスタンスを生成する5つのステップ

Objective-Cプログラミングの基本をカラフルな図解で学ぶ Objctive-C
この記事は約23分で読めます。

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

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

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

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

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

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

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

はじめに

プログラミングを始めたばかりで、Objective-Cの世界に足を踏み入れたあなたにとって、インスタンス生成は基本中の基本です。

インスタンスとは、プログラムが具体的な作業を行うためのデータや命令の集まりであり、クラスという設計図に基づいて作られます。

この記事を読むことで、Objective-Cにおけるインスタンス生成の5つの具体的なステップを理解し、あなたもこの重要なスキルをマスターできるようになるでしょう。

●Objective-Cとは

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

AppleのiOSやmacOSのアプリケーション開発に長らく使用され、Swiftに取って代わられるまで主流の言語でした。

しかし、既存のアプリケーションの保守や、特定のライブラリの利用のために今でも学ぶ価値は大いにあります。

○Objective-Cの歴史と特徴

Objective-Cは1980年代にBrad CoxとTom Loveによって開発されました。

Smalltalkのオブジェクト指向の概念と、C言語のパフォーマンスを組み合わせた言語として知られています。

その特徴は、動的な型付け、メッセージパッシング、強力なランタイムがあり、これらは今日のアプリ開発においても非常に重要な要素です。

Objective-CはAppleのNeXTSTEP OSの開発に採用され、その後、Mac OS XとiOSの標準開発言語となりました。

Objective-CはC言語と完全に互換性があり、C言語のコードをそのまま利用できることも大きな特徴です。

一方で、Swiftと比べて構文が複雑で、学習曲線が急であるとも言われていますが、その分、広い範囲の機能を有しているとも評価されています。

●インスタンス生成の基本

インスタンス生成は、プログラム内で操作するデータの実体を作ることです。

Objective-Cにおいて、インスタンス生成は重要なプロセスであり、プログラムが動的にデータを扱うための出発点となります。

インスタンスはクラスから生成されるため、クラスは車の設計図であり、インスタンスはその設計図から作られた実際の車に例えることができます。

Objective-Cでのインスタンス生成は、主に新たなオブジェクトをメモリ上に確保し、そのオブジェクトに特定の初期値を設定する過程を含みます。

○クラスとインスタンスの関係

クラスはオブジェクトの青写真であり、メソッド(オブジェクトが実行できる機能)とプロパティ(オブジェクトが持つデータ)の定義を含んでいます。

Objective-Cでは、クラスを定義することで、任意のデータ型のインスタンスを生成できるようになります。

インスタンスはクラスに定義されたメソッドを実行することができ、クラスに記述された振る舞いを具現化したものです。

○インスタンス生成のためのコード構造

Objective-Cでインスタンスを生成するには、まずクラスを定義する必要があります。

クラス定義は通常、ヘッダファイル(.h)と実装ファイル(.m)に分けて行われます。

ヘッダファイルには外部からアクセス可能なメソッドやプロパティが宣言され、実装ファイルにはその具体的な実装が記述されます。

インスタンス生成のプロセスは、次のように進みます。

まず、クラスの新しいインスタンスをメモリに確保するために、allocメソッドを使用します。

次に、そのインスタンスに初期値を設定するためにinitメソッドを呼び出します。

このallocinitを組み合わせた操作を「アロケーション(確保)-イニシャライゼーション(初期化)パターン」と呼びます。

●インスタンス生成方法の詳細

Objective-Cでインスタンスを生成する方法は複数存在しますが、最も基本的な手法はallocとinitの組み合わせを使用することです。

これは、メモリ上に新しいオブジェクトのためのスペースを確保し(alloc)、そのオブジェクトを初期化する(init)という二段階のプロセスに分かれています。

初期化とは、インスタンス変数に初期値を設定することを指し、オブジェクトが適切な状態で使用されるために不可欠です。

○サンプルコード1:基本的なインスタンス生成

Objective-Cでのインスタンス生成を見る前に、まずはシンプルなクラス定義から始めましょう。

下記の例は、一つのプロパティを持つPersonクラスを定義し、そのインスタンスを生成する方法を表しています。

// Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, strong) NSString *name;

- (id)initWithName:(NSString *)name;

@end

// Person.m
#import "Person.h"

@implementation Person

- (id)initWithName:(NSString *)aName {
    self = [super init];
    if (self) {
        _name = aName;
    }
    return self;
}

@end

このコードでは、PersonクラスがNSObjectクラスを継承していることを表しています。

そして、nameというプロパティを持っており、initWithName:メソッドでそのプロパティを初期化できるようにしています。

続いて、このPersonクラスからインスタンスを生成する方法を見てみましょう。

// main.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // インスタンスを生成して初期化
        Person *person = [[Person alloc] initWithName:@"John Doe"];
        NSLog(@"Created a Person instance with name: %@", person.name);
    }
    return 0;
}

この例では、allocを使ってPersonクラスの新しいインスタンスをメモリ上に確保し、initWithName:メソッドで名前を”John Doe”に設定しています。

そして、NSLog関数を使って、生成したインスタンスのnameプロパティの値をコンソールに出力しています。

このコードを実行すると、「Created a Person instance with name: John Doe」という文がコンソールに表示されます。

○サンプルコード2:イニシャライザを使用したインスタンス生成

インスタンス生成においては、カスタムイニシャライザを使用することで、より柔軟にインスタンスの状態をコントロールできます。

イニシャライザは、クラスに必要な初期化ロジックをカプセル化するメソッドであり、特定のパラメータを持つインスタンスを作成するのに便利です。

ここでは、カスタムイニシャライザを持つVehicleクラスの例を紹介します。

// Vehicle.h
#import <Foundation/Foundation.h>

@interface Vehicle : NSObject

@property (nonatomic, assign) int numberOfWheels;

- (id)initWithWheels:(int)wheels;

@end

// Vehicle.m
#import "Vehicle.h"

@implementation Vehicle

- (id)initWithWheels:(int)wheels {
    self = [super init];
    if (self) {
        _numberOfWheels = wheels;
    }
    return self;
}

@end

この例では、VehicleクラスにはnumberOfWheelsというプロパティがあり、initWithWheels:イニシャライザを使用て、車輪の数を指定してインスタンスを初期化できるようになっています。

実際にVehicleクラスのインスタンスを生成してみると、次のようになります。

// main.m
#import <Foundation/Foundation.h>
#import "Vehicle.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // インスタンスを生成して初期化
        Vehicle *bike = [[Vehicle alloc] initWithWheels:2];
        NSLog(@"Created a Vehicle instance with wheels: %d", bike.numberOfWheels);
    }
    return 0;
}

このコードを実行すると、Created a Vehicle instance with wheels: 2というメッセージがコンソールに出力され、2輪の車輪を持つVehicleクラスのインスタンスが生成されたことがわかります。

○サンプルコード3:クラスファクトリメソッドによるインスタンス生成

クラスファクトリメソッドは、インスタンス生成のための便利なパターンで、目的のクラスのインスタンスを返すクラスメソッドです。

これにより、allocとinitを個別に呼び出す代わりに、一つのメソッドでインスタンスを生成できます。

ここでは、クラスファクトリメソッドを使用してインスタンスを生成するコード例を紹介します。

// MyClass.h
#import <Foundation/Foundation.h>

@interface MyClass : NSObject
+ (instancetype)myClassWithParameter:(NSString *)param;
@end

// MyClass.m
#import "MyClass.h"

@implementation MyClass

+ (instancetype)myClassWithParameter:(NSString *)param {
    MyClass *instance = [[MyClass alloc] init];
    // ここでパラメータに基づいた初期化を行う
    return instance;
}

@end

このコードでは、MyClassクラスにmyClassWithParameter:というクラスファクトリメソッドを実装しています。

そして、このメソッド内でallocとinitを呼び出し、必要な初期化を行った後にインスタンスを返しています。

クラスファクトリメソッドの使用は、コードの可読性と記述の簡潔さを向上させるために有効です。

この方法を用いたインスタンス生成の実行結果は、新しく初期化されたMyClassインスタンスの取得になります。

これは、同じクラスのインスタンスを複数回生成する際にも、コードの重複を避けるのに役立ちます。

○サンプルコード4:カスタムクラスでのインスタンス生成

Objective-Cでは、カスタムクラスを作成して、特定の目的に合わせてインスタンス生成をカスタマイズできます。

下記のサンプルコードは、特定の設定を持つカスタムクラスのインスタンスを生成する方法を表しています。

// CustomClass.h
#import <Foundation/Foundation.h>

@interface CustomClass : NSObject
@property (nonatomic, strong) NSString *customProperty;
- (instancetype)initWithCustomProperty:(NSString *)property;
@end

// CustomClass.m
#import "CustomClass.h"

@implementation CustomClass

- (instancetype)initWithCustomProperty:(NSString *)property {
    if ((self = [super init])) {
        _customProperty = property;
    }
    return self;
}

@end

この例ではCustomClassinitWithCustomProperty:というカスタムイニシャライザを実装しています。

このイニシャライザは、カスタムプロパティを初期化パラメータとして受け取り、その値をインスタンスのプロパティに設定しています。

このカスタムクラスのインスタンス生成を行うことで、特定の設定が事前に適用された状態のオブジェクトを作成することが可能になります。

これにより、設定が複雑なオブジェクトや、特別な準備が必要なオブジェクトの生成を簡単に行うことができます。

○サンプルコード5:インスタンス生成時のエラー処理

インスタンス生成時には、エラーが発生する可能性も考慮する必要があります。

例えば、イニシャライザ内でエラーが発生した場合には、nilを返して、インスタンス生成が失敗したことを表すことができます。

ここではエラー処理を伴うインスタンス生成のサンプルコードを紹介します。

// ErrorHandlingClass.h
#import <Foundation/Foundation.h>

@interface ErrorHandlingClass : NSObject
- (instancetype)initWithParameter:(NSString *)param error:(NSError **)error;
@end

// ErrorHandlingClass.m
#import "ErrorHandlingClass.h"

@implementation ErrorHandlingClass

- (instancetype)initWithParameter:(NSString *)param error:(NSError **)error {
    self = [super init];
    if (self) {
        if ([param isEqualToString:@"Error"]) {
            if (error) {
                *error = [NSError errorWithDomain:@"CustomErrorDomain" code:400 userInfo:nil];
            }
            return nil; // エラー発生時はnilを返す
        }
        // その他の初期化処理
    }
    return self;
}

@end

このコードでは、initWithParameter:error:メソッドを使用しています。

このメソッドはパラメータとして渡された文字列が”Error”の場合、エラーオブジェクトを生成し、ポインタを介して呼び出し元にエラー情報を返します。

そして、エラーが検出された場合には、nilを返してインスタンス生成が失敗したことを表しています。

●インスタンス生成の応用例

インスタンス生成は、単にオブジェクトを作る以上の多様な使い道があります。

Objective-Cでは、生成したインスタンスをコレクションに格納したり、アプリケーションの実行中に動的にプロパティを変更するなど、様々な方法でインスタンスを利用できます。

ここでは、これらの応用的な使い方を解説します。

○サンプルコード6:インスタンスを配列に格納する

Objective-Cで生成したインスタンスをNSArrayやNSMutableArrayなどの配列に格納することで、複数のオブジェクトをまとめて管理することができます。

下記のコードでは、複数のPersonインスタンスを配列に格納し、それを利用する一連のプロセスを表しています。

// main.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // Personクラスのインスタンスを作成
        Person *person1 = [[Person alloc] initWithName:@"John"];
        Person *person2 = [[Person alloc] initWithName:@"Jane"];
        Person *person3 = [[Person alloc] initWithName:@"Doe"];

        // インスタンスをNSArrayに格納
        NSArray *personArray = @[person1, person2, person3];

        // 配列の内容を繰り返し処理する
        for (Person *person in personArray) {
            NSLog(@"Person name is: %@", person.name);
        }
    }
    return 0;
}

この例では、まず3つのPersonインスタンスを生成し、それらをNSArrayオブジェクトに格納しています。

その後、for-inループを使って配列の各要素にアクセスし、それぞれのPersonオブジェクトのnameプロパティをコンソールに出力しています。

この方法を使用することで、オブジェクトの集合に対する操作を簡単に行えます。

○サンプルコード7:プロパティを持つインスタンスの生成

オブジェクト指向プログラミングでは、オブジェクトのプロパティを通じて状態を管理します。

Objective-Cにおいてプロパティを持つインスタンスを生成する際には、プロパティの初期値を設定することが一般的です。

下記のコードスニペットは、プロパティを持つカスタムクラスのインスタンスを生成し、初期値を設定するプロセスを表しています。

// CustomClass.h
#import <Foundation/Foundation.h>

@interface CustomClass : NSObject
@property (nonatomic, strong) NSString *customProperty;
// その他のプロパティも同様に定義可能
@end

// CustomClass.m
#import "CustomClass.h"

@implementation CustomClass
// イニシャライザやその他のメソッドの実装
@end

// main.m
#import "CustomClass.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // インスタンス生成とプロパティの初期化
        CustomClass *instance = [[CustomClass alloc] init];
        instance.customProperty = @"Initial value";

        NSLog(@"CustomClass instance has a property value: %@", instance.customProperty);
    }
    return 0;
}

このコードではCustomClassという新しいクラスにcustomPropertyというプロパティを定義しています。

メイン関数内でCustomClassの新しいインスタンスを生成し、customPropertyの値を設定して、その値をログに出力しています。

これにより、特定の初期設定を持つインスタンスを容易に作成できます。

○サンプルコード8:マルチスレッド環境でのインスタンス生成

マルチスレッドプログラミングでは、異なるスレッド上で動作するインスタンスを生成する際に、スレッドセーフなコーディングを心がける必要があります。

Objective-Cでは、@synchronizedブロックやGrand Central Dispatch(GCD)などの機能を用いてスレッドセーフな環境を実現できます。

ここでは、GCDを使用してスレッドセーフにインスタンスを生成し、それを利用する方法のサンプルコードを紹介します。

// ThreadSafeClass.h
#import <Foundation/Foundation.h>

@interface ThreadSafeClass : NSObject
// スレッドセーフにするためのプロパティやメソッドを定義
@end

// ThreadSafeClass.m
#import "ThreadSafeClass.h"

@implementation ThreadSafeClass
// インスタンス生成と操作に関わるメソッドを実装
@end

// main.m
#import "ThreadSafeClass.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // GCDを使用してバックグラウンドでインスタンスを生成
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            ThreadSafeClass *instance = [[ThreadSafeClass alloc] init];
            // バックグラウンドスレッドでのインスタンス操作
        });

        // メインスレッドでのインスタンス操作
        ThreadSafeClass *mainInstance = [[ThreadSafeClass alloc] init];
        // メインスレッドで安全に操作できる
    }
    return 0;
}

この例では、dispatch_async関数を使用して非同期に新しいバックグラウンドスレッドを生成し、そのスレッド上でThreadSafeClassのインスタンスを生成しています。

GCDは、タスクをシンプルかつ安全に並行実行するための強力なツールです。

このようにして生成されたインスタンスは、そのスレッド固有のコンテキスト内で安全に操作することができます。

●インスタンス生成時の注意点と対処法

Objective-Cにおけるインスタンス生成には、いくつかの注意点があります。

注意点を理解し、適切に対処することで、プログラムのバグやメモリリークを防ぎ、より効率的なコードを書くことが可能になります。

○メモリ管理の基本

メモリ管理はObjective-Cでのプログラミングにおいて非常に重要なコンセプトです。

Objective-Cでは、過去にはマニュアルでのメモリ管理が一般的でしたが、現在ではARCの採用により多くのメモリ管理タスクが自動化されています。

ARCを使用している場合、開発者はインスタンスが不要になったタイミングでコンパイラによって自動的にメモリが解放されるため、通常はreleasedeallocメソッドを意識する必要はありません。

しかし、ARCが管理しきれない部分(例えば循環参照)に対しては、開発者が手動で管理することが必要です。

下記のコードは、循環参照を避けるために弱参照を使用する例です。

// MyClass.h
#import <Foundation/Foundation.h>

@interface MyClass : NSObject
@property (nonatomic, weak) id delegate;
@end

この例では、delegateプロパティを弱参照(weak)として宣言しており、delegateがインスタンスを保持している間、MyClassのインスタンスが解放されると自動的にnilになります。

これにより、循環参照によるメモリリークを防ぐことができます。

○イニシャライザのカスタマイズとエラー処理

イニシャライザをカスタマイズすることで、インスタンス生成時に特定のロジックを実行できます。

ただし、初期化中に何らかの理由でインスタンスの状態が無効になる可能性があるため、エラー処理が重要になります。

下記のコードは、イニシャライザでエラー処理を行う例です。

// MyClass.h
#import <Foundation/Foundation.h>

@interface MyClass : NSObject
- (instancetype)initWithParameter:(NSString *)param error:(NSError **)error;
@end

// MyClass.m
#import "MyClass.h"

@implementation MyClass

- (instancetype)initWithParameter:(NSString *)param error:(NSError **)error {
    if ((self = [super init])) {
        if ([param isEqualToString:@"InvalidParameter"]) {
            if (error) {
                *error = [NSError errorWithDomain:@"MyErrorDomain" code:100 userInfo:@{NSLocalizedDescriptionKey: @"Invalid parameter passed to initializer."}];
            }
            return nil; // エラー時はnilを返す
        }
        // 初期化成功時の処理
    }
    return self;
}

この例では、無効なパラメータが渡された場合に、エラーオブジェクトを生成して呼び出し元に渡し、nilを返しています。

このようにしてエラー処理を行うことで、プログラムの安定性を高めることができます。

●カスタマイズ方法

Objective-Cでは、カスタマイズ可能なインスタンス生成方法を提供することで、開発者がより柔軟にオブジェクトを利用できるようになっています。

カスタマイズは、アプリケーションの特定の要求に合わせてオブジェクトの振る舞いを調整する際に特に有用です。

ここでは、Objective-Cでのインスタンスのカスタマイズ方法をいくつかの例を通して紹介します。

○インスタンスのカスタマイズ例

例えば、特定のアプリケーションでは、特定の状態で初期化されたオブジェクトが必要になることがあります。

ここでは、インスタンスの状態をカスタマイズする際の一般的なアプローチを表すコードを紹介します。

// CustomInitializerClass.h
#import <Foundation/Foundation.h>

@interface CustomInitializerClass : NSObject

@property (nonatomic, strong) NSString *someProperty;

- (instancetype)initWithCustomSetup:(NSString *)setupInfo;

@end

// CustomInitializerClass.m
#import "CustomInitializerClass.h"

@implementation CustomInitializerClass

- (instancetype)initWithCustomSetup:(NSString *)setupInfo {
    self = [super init];
    if (self) {
        // カスタムセットアップを行う
        _someProperty = [setupInfo copy];
        // 必要に応じて他の初期化コードをここに追加
    }
    return self;
}

@end

このコードスニペットでは、CustomInitializerClassinitWithCustomSetup:メソッドを実装しています。

このメソッドは、インスタンスの初期化時に特定の設定情報を受け取り、その情報を使ってオブジェクトの状態を設定します。

このようにして、特定の状態で初期化されたインスタンスを容易に作成することが可能です。

まとめ

この記事を通じて、Objective-Cでのインスタンス生成の基本から応用、注意点と対処法まで、幅広い情報を解説しました。

Objective-Cを用いたアプリケーション開発では、これらの基本をマスターすることが非常に重要です。

今後も新しい技術が登場する可能性がありますが、基本をしっかりと理解していれば、変化に柔軟に対応できるでしょう。

このガイドが読者のObjective-C学習の一助となり、より良いアプリケーション開発の基礎を築くことができれば幸いです。