読み込み中...

初心者向け!Objective-Cで遅延実行の10のテクニック

初心者が学ぶObjective-Cの遅延実行テクニックとサンプルコードのイメージ Objctive-C
この記事は約21分で読めます。

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

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

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

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

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

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

はじめに

プログラミングを学び始めたばかりの初心者にとって、Objective-Cのような伝統ある言語を習得することは、次世代のアプリ開発につながる重要な一歩です。

この記事では、Objective-Cで遅延実行を行うための10のテクニックを紹介します。

サンプルコードと共に基本から応用までをわかりやすく解説するので、ぜひ最後までご覧ください。

●Objective-Cとは

Objective-Cは、C言語にオブジェクト指向の概念を加えたプログラミング言語です。

アップル社によってiOSやmacOSのアプリケーション開発に長らく使用されてきました。

そのシンタックスは、人間の言語に近い表現力があり、習得が容易なのが特徴です。

○Objective-Cの歴史

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

彼らの目的は、ソフトウェアの再利用性を高めることにありました。

1988年にはNeXT社(後のアップル社)がこの言語を採用し、後のiOSやmacOSの開発の基礎を築きました。

○Objective-Cの特徴

Objective-Cの最大の特徴は、Smalltalk言語の影響を受けたメッセージ指向のプログラミングが可能であることです。

また、ランタイム時の型決定(ダイナミックタイピング)やカテゴリーという機能により、既存のクラスにメソッドを追加することなどが可能です。

これにより、柔軟かつ強力なコードの記述が行えます。

さらに、Objective-CはC言語と完全に互換性があるため、C言語のライブラリも利用できるという利点もあります。

●プログラミングの基礎

プログラミングとは、コンピュータに対して指示を出し、期待する動作を実現するための技術です。

プログラミングを行うには、まずその基礎から理解する必要があります。

ここでは、プログラミングの初歩として重要な「変数」と「関数」について、Objective-Cの言語を例に説明します。

○変数とは何か?

変数とは、データを一時的に保存するための容器のようなものです。

プログラミング言語においては、変数には名前(変数名)があり、この名前を通じてデータにアクセスすることができます。

Objective-Cでは、変数を宣言する際には型を指定します。これは、どの種類のデータを保存するかを明示するためです。

例えば、整数を保存する変数の宣言は次のようになります。

int number = 10;

このコードでは、int という型を使って number という名前の変数を宣言し、その変数に 10 という値を代入しています。

これにより、number という名前を通じて、整数の 10 にアクセスできるようになります。

この変数を使用して、例えば数値を画面に表示するコードは次の通りです。

NSLog(@"numberの値は: %d", number);

この場合、コンソールには「numberの値は: 10」と表示されます。

変数 number に別の値を代入することで、保存されているデータを更新することが可能です。

○関数とは何か?

関数とは、特定の処理を一まとめにしたコードの塊であり、必要に応じて何度でもその処理を実行できるようにするための仕組みです。

関数は、入力値(引数)に対して処理を行い、結果(戻り値)を返すことができます。

Objective-Cで関数を定義するには、次のように書きます。

- (int)add:(int)a to:(int)b {
    return a + b;
}

このコードでは、add:to: という名前の関数を定義しており、2つの整数型の引数 ab を受け取り、それらを加算した結果を戻り値として返します。

この関数を呼び出すことで、指定された2つの数値を加算する処理を簡単に再利用することができます。

関数を実際に使用する例は次の通りです。

int result = [self add:5 to:10];
NSLog(@"結果は: %d", result);

このコードを実行すると、add:to: 関数が 510 の加算を行い、結果として 15 を返します。

その結果は result 変数に保存され、画面には「結果は: 15」と表示されます。

●遅延実行とは

プログラミングにおいて、「遅延実行」とは、あるコードブロックや関数の実行を意図的に遅らせ、特定のタイミングで実行させる技術です。

これは、ユーザーのアクションを待つような場合や、リソースの読み込みが完了するのを待つなど、多様なシナリオで利用されます。

○遅延実行の必要性

遅延実行は、アプリケーションがスムーズに動作するようにするために不可欠です。

例えば、データがロードされるのを待ってからユーザーに情報を表示したい場合や、ユーザーが何かしらのアクションを完了させた後に処理を行いたい場合などが挙げられます。

遅延実行を上手く使うことで、アプリケーションのパフォーマンスを向上させ、ユーザー体験を改善することができます。

○Objective-Cでの遅延実行の仕組み

Objective-Cでは、遅延実行を実現するためにいくつかの方法が提供されています。

主にNSTimer、GCD(Grand Central Dispatch)、そしてブロックを使用する方法などがあります。

これらの技術を使って、開発者は指定した時間が経過した後や、特定のイベントが発生した後にコードを実行させることができます。

●Objective-Cにおける遅延実行の基本

Objective-Cでプログラミングを行う際に避けて通れないのが「遅延実行」です。

これは、あるコードの実行を予定している直ちにではなく、特定の時間が経過した後に行いたい場合に用いられるテクニックです。

iOS開発においては、ユーザーインターフェイスの更新やネットワークリクエストの後処理など、様々な場面で遅延実行は活用されます。

ここでは、Objective-Cにおける遅延実行の基本について、初心者の方にも理解しやすいように詳細なサンプルコードを交えてご紹介します。

○サンプルコード1:基本的な遅延実行の実装

Objective-Cにおける最もシンプルな遅延実行の方法はperformSelector:withObject:afterDelay:メソッドを使うことです。

このメソッドを利用することで、特定のオブジェクトに対してメッセージを送り、その実行を指定した秒数後に行うようスケジュールできます。

[self performSelector:@selector(myMethod) withObject:nil afterDelay:5.0];

このコードではselfオブジェクトに対してmyMethodメソッドを送信しています。

この例ではmyMethodを5秒後に実行しています。

myMethodは引数をとらないメソッドですが、必要に応じてwithObject:の部分にオブジェクトを渡すことも可能です。

このコードが実行された場合、5秒間何も起こらず、その後myMethodが呼び出されることになります。

実際にmyMethod内で例えばログを出力する処理を書いておけば、その動作を目で見て確認できるでしょう。

○サンプルコード2:NSTimerを使った遅延実行

次に、NSTimerを使って遅延実行を行う例を見ていきます。

NSTimerはスケジュールされた時間が来ると特定のメッセージをターゲットに送るためのオブジェクトです。

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0
                                                  target:self
                                                selector:@selector(myMethod)
                                                userInfo:nil
                                                 repeats:NO];

このコードでは、5秒後に一度だけselfmyMethodを呼び出すタイマーを作成しています。

repeatsパラメータがNOに設定されているため、一度実行された後にはタイマーは無効になります。

userInfoを使うことで、myMethodが実行される際に追加の情報を渡すことも可能です。

実行後、5秒後にmyMethodが実行され、もしmyMethod内にログ出力の処理があれば、その時点でコンソールに表示されることになります。

○サンプルコード3:GCDを使った遅延実行

最後に、Grand Central Dispatch(GCD)を使用した遅延実行について説明します。

GCDはマルチコアプロセッサを効率的に使用するためのテクノロジーであり、非同期実行を簡単に行うことができます。

dispatch_after(dispatch_time(DIS

PATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self myMethod];
});

このコードでは、メインキューに5秒後に実行するブロックをスケジュールしています。

dispatch_after関数は指定したディスパッチキュー上で、指定した時間が経過した後にブロックを非同期に実行します。

myMethodはこのブロック内で呼び出され、実行されます。

このコードを実行すると、メインスレッド上で5秒後にmyMethodが実行されるため、たとえばUIの更新などメインスレッドでの作業が必要な場合に適しています。

●遅延実行の応用例

遅延実行の技術は、様々なシーンで有効です。

例えば、ユーザーがボタンを押した後に結果を表示する前にローディング画面を一定時間表示したい場合や、ネットワークリクエストを送信した後に応答を待つ間にユーザーに対して何らかのフィードバックを提供したい場合などです。

これらのシーンでObjective-Cを使用して遅延実行を実装する方法を見ていきましょう。

○サンプルコード4:ユーザーインタラクション後の遅延実行

Objective-Cでは、Grand Central Dispatch(GCD)を使用して遅延実行を行うことが一般的です。

下記のサンプルコードでは、ユーザーがボタンをタップした後に5秒間待ってからメソッドを実行する例を表しています。

// ボタンがタップされたときに呼ばれるメソッド
- (void)userDidTapButton {
    // メインキューに5秒後に実行するブロックをスケジュールする
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self methodToBeExecutedAfterDelay];
    });
}

// 遅延実行されるメソッド
- (void)methodToBeExecutedAfterDelay {
    // ここで何かの処理を行う
    NSLog(@"This method is executed after a 5 seconds delay");
}

このコードでは、dispatch_after関数を使用して、現在の時刻から5秒後にmethodToBeExecutedAfterDelayメソッドを実行するようスケジュールしています。

実際にこのコードが実行されると、ユーザーがボタンをタップしてから5秒間の遅延の後に、コンソールにログが出力されます。

○サンプルコード5:ネットワークリクエスト後の遅延実行

ネットワークリクエストを送信し、そのレスポンスを受け取るまでの間にユーザーにフィードバックを提供することは、良いユーザーエクスペリエンスを提供する上で重要です。

下記のコードは、ネットワークリクエストを送信した後、応答を受け取る前に一定時間処理を遅延させる方法を表しています。

// ネットワークリクエストをシミュレートするメソッド
- (void)simulateNetworkRequest {
    NSLog(@"Network request started");

    // ダミーのネットワークリクエストを3秒後に完了するように

する
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self handleNetworkResponse];
    });
}

// ネットワークレスポンスを処理するメソッド
- (void)handleNetworkResponse {
    NSLog(@"Network response received");
    // 応答を受け取った後の処理をここに書く
}

このコードは、ネットワークリクエストを表すsimulateNetworkRequestメソッドと、その応答を処理するhandleNetworkResponseメソッドを定義しています。

dispatch_afterを使って3秒後にレスポンスを受け取ったと仮定してhandleNetworkResponseメソッドを実行します。

これにより、実際にはネットワークリクエストをしていませんが、3秒後に「Network response received」というログがコンソールに表示されます。

これは、実際のネットワーク応答が来た場合にユーザーインターフェースを更新するための準備をする場面で応用できます。

○サンプルコード6:アニメーションと遅延実行

ユーザーインターフェースのアニメーションはアプリケーションの魅力を高めます。

Objective-CではUIViewのアニメーションブロックと遅延実行を組み合わせて、スムーズなユーザーエクスペリエンスを実現できます。

下記のサンプルコードでは、アニメーション後に特定の処理を遅延実行する方法を表しています。

// UIViewアニメーションと遅延実行の組み合わせ
- (void)animateViewAndDelayExecution {
    [UIView animateWithDuration:1.0 animations:^{
        // アニメーションを実行するコード。例えばviewの透明度を変更。
        self.myView.alpha = 0.0;
    } completion:^(BOOL finished) {
        // アニメーションが完了した後、遅延実行するコード
        if (finished) {
            [self performSelector:@selector(delayedAction) withObject:nil afterDelay:2.0];
        }
    }];
}

// 遅延実行されるメソッド
- (void)delayedAction {
    // 遅延実行する具体的な処理をここに記述
    self.myView.alpha = 1.0;
}

このコードではanimateWithDuration:animations:completion:を使って、まずビューの透明度を1秒かけて0にします。

アニメーションの完了後のcompletionブロック内でperformSelector:withObject:afterDelay:を呼び出し、さらに2秒遅らせてdelayedActionメソッドを実行します。

delayedActionメソッド内では、ビューの透明度を元に戻す処理をしています。

このサンプルコードを実行すると、ビューはまず徐々に透明になり、その後2秒間何も起こらず、最終的に元の不透明な状態に戻ります。

○サンプルコード7:複数の遅延実行を管理する

アプリケーションにおいて複数の遅延実行を管理することは一般的なシナリオです。

Objective-Cで複数の遅延実行を効率よく管理するには、タイマーやGCD(Grand Central Dispatch)のキューを利用することができます。

下記のコードは、GCDを用いて複数の遅延実行を制御する例です。

// GCDを使用して複数の遅延実行を管理する
- (void)manageMultipleDelayedTasks {
    // タスク1を遅延実行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // ここに遅延実行したいコードを書く(タスク1)
        NSLog(@"Task 1 is executed");
    });

    // タスク2を遅延実行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // ここに遅延実行したいコードを書く(タスク2)
        NSLog(@"Task 2 is executed");
    });
}

// このメソッドを呼び出すと、最初に「Task 1 is executed」というログが2秒後に、
// 次に「Task 2 is executed」というログがそのさらに2秒後に出力される。

このコードでは、dispatch_after関数を使用して2つの異なるタスクを異なる遅延時間で実行しています。

最初のタスクは2秒後に、次のタスクは4秒後にそれぞれメインスレッドで実行されます。

dispatch_timeを使うことで、指定した時間後にブロック内のコードが実行されるようにスケジュールすることができます。

このサンプルコードの実行結果としては、まずコンソールに「Task 1 is executed」と表示され、さらに2秒後に「Task 2 is executed」と表示されます。

こうすることで、時間的に互いに干渉しないように複数のタスクを管理できます。

●遅延実行の注意点と対処法

遅延実行はObjective-Cプログラミングにおいて重要な技術ですが、正しく理解し適切に使用しないと予期せぬバグやパフォーマンスの問題を引き起こす可能性があります。

ここでは遅延実行を行う際に留意すべき点とその対処法を解説します。

○メモリ管理の注意点

Objective-CではARC(Automatic Reference Counting)によるメモリ管理が一般的ですが、遅延実行を行う際には特にメモリリークに注意する必要があります。

遅延実行のブロック内でselfを参照する場合、強参照サイクルが発生し、メモリリークを引き起こすことがあります。

対処法としては、ブロック内でselfを弱参照(weak reference)として定義することで、強参照サイクルを防ぎます。

下記のサンプルコードでは、__weakキーワードを使用してselfを弱参照にしています。

__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
        // ここでself(strongSelf)を安全に参照できます
        [strongSelf doSomething];
    }
});

このコードでは、遅延実行されるブロックの外でweakSelfとしてselfを弱参照にし、ブロック内でstrongSelfとして弱参照から強参照に変換しています。

これにより、ブロックが実行されるタイミングでselfがまだ存在していれば操作を行い、そうでなければ何も行わないようになっています。

○遅延実行のキャンセル方法

一度スケジュールされた遅延実行をキャンセルする直接的な方法はObjective-Cにはありませんが、実行前に条件をチェックすることで実質的なキャンセルを行うことができます。

例えば、ユーザーが画面から離れたことを検出してから、あるタスクをキャンセルしたい場合、次のようなフラグを用いたコードが考えられます。

@property (assign, nonatomic) BOOL shouldCancelTask;

// ...

// タスクをスケジュールする前にフラグを設定
self.shouldCancelTask = NO;

// 遅延実行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    if (!self.shouldCancelTask) {
        // 実行したいコード
    }
});

// 何らかの条件でタスクをキャンセルしたい場合
self.shouldCancelTask = YES;

このコードでは、shouldCancelTaskプロパティを使用して遅延実行するタスクが実際に実行される前に条件をチェックしています。

もしshouldCancelTaskYESに設定されていれば、タスクは実行されません。

これにより、特定の条件下でタスクを「キャンセル」することができます。

●カスタマイズ方法

遅延実行のカスタマイズとは、実行の遅延時間を変更する方法や条件に応じて遅延実行をコントロールする手法を指します。

Objective-Cでは、NSTimerやGrand Central Dispatch(GCD)などを使ってこのカスタマイズを行うことができます。

○遅延時間の調整

遅延時間の調整は、特定のタスクを何秒後に実行するかを指定することで、例えばユーザーがあるアクションを行った後、短い時間待ってから次の処理を始めるというシナリオで有用です。

この調整はNSTimerやGCDの遅延実行関数を用いて行います。

このサンプルコードでは、NSTimerを使用して5秒後に特定のメソッドを実行する方法を表しています。

// NSTimerを使用して遅延実行を行うサンプルコード
[NSTimer scheduledTimerWithTimeInterval:5.0
                                  target:self
                                selector:@selector(delayedMethod)
                                userInfo:nil
                                 repeats:NO];

// 5秒後に実行されるメソッド
- (void)delayedMethod {
    // ここに遅延して実行したい処理を記述します
    NSLog(@"5秒後に実行されるメソッドが呼ばれました");
}

このコードではNSTimerを使って、scheduledTimerWithTimeInterval メソッドにより5秒間の遅延を設定し、delayedMethod メソッドを実行しています。

この例では、delayedMethod が5秒後に実行され、コンソールにその旨が表示されます。

○遅延実行の条件設定

遅延実行の条件設定とは、特定の条件が満たされた時だけ遅延実行を行うことです。

例えば、ネットワークの状態が良いときだけデータをフェッチするといった場合に適しています。

この条件設定はGCDのディスパッチキューを使用して実現することができます。

このサンプルコードでは、GCDを使用して条件を満たした場合にのみ遅延実行を行う方法を表しています。

// GCDを使用して条件付きで遅延実行を行うサンプルコード
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    if (/* 条件をチェック */ YES) {
        // 条件を満たした場合に実行したい処理を記述します
        NSLog(@"条件を満たしているため、3秒後に処理を実行しました");
    } else {
        // 条件を満たしていない場合の処理を記述します
        NSLog(@"条件を満たしていないため、処理をスキップしました");
    }
});

このコードではdispatch_after 関数を使って、3秒後に処理を実行する遅延を設定しています。

遅延実行の中で条件チェックを行い、条件を満たしている場合のみ指定の処理を実行します。

この例では、条件が真の場合に3秒後に処理が実行されることをコンソールに表示しています。

まとめ

Objective-Cにおける遅延実行は、アプリケーションのパフォーマンスを向上させたり、ユーザーエクスペリエンスを向上させるために非常に重要です。

本記事で紹介したテクニックを使うことで、さまざまな条件下でコードの実行を適切にコントロールすることができます。

この記事では、Objective-Cでの基本的な遅延実行の実装から始め、NSTimer、GCD(グランドセントラルディスパッチ)を用いた遅延実行、ユーザーインタラクションやネットワークリクエスト完了後の遅延実行、アニメーションと組み合わせた遅延実行、複数の遅延実行を管理する方法などを見てきました。

それぞれのテクニックには、状況に応じたカスタマイズが可能です。

たとえば、遅延時間を調整したり、特定の条件下でのみ遅延実行を行うようにするなど、プログラムの要件に合わせた柔軟な実装が可能です。

遅延実行をプログラムに組み込む際には、それがユーザーにとって最も自然な形で経験されるように、慎重に計画することが重要です。

コードの実行を適切にスケジュールすることで、スムーズなアプリケーションの動作と、快適なユーザー体験を実現できるでしょう。

このガイドで説明したサンプルコードと説明を参考に、Objective-Cにおける遅延実行の理解を深め、あなたのアプリケーションに最適な実装を見つけ出してください。

この記事が、より輝かしい開発者としてのキャリアを築くための確かな基盤となることを願っています。