ブロッキング API vs. ノンブロッキング API

新規ユーザーの登録やデータのアップロード等、Kii Cloud が提供する多くのメソッドはサーバーとの通信が発生する関係で処理完了までに時間を要します。このようなメソッドに対して、Kii Cloud SDK for iOS はブロッキング API とノンブロッキング API の双方を提供しています。

モバイルアプリのスレッドモデル

Kii Cloud SDK では、ユーザーインターフェイスを実行するスレッドからネットワークアクセスの処理を直接実行するのは避ける必要があります。

Android、iOS、HTML5 では、イベントドリブンなアーキテクチャを採用しています。ボタンのクリックや、タッチ操作によるスクロールといったイベントが発生すると、それらを契機にイベントハンドラーが呼び出され、処理が実行されます。ユーザーインターフェイスに対するすべての処理はユーザーインターフェイス専用のスレッドで実行されるため、1 つの処理に手間取ると、画面全体の操作性が低下します。

一方、Kii Cloud へのネットワークアクセスは通常でも数ミリ~数十ミリ秒、通信環境によっては数秒単位での遅延も予想されます。こうした処理をユーザーインターフェイススレッドから呼び出すと、操作性が悪化します。

クライアント SDK の API

Kii Cloud のクライアント SDK では、ネットワークアクセスを伴う API と伴わない API があります。さらに、ネットワークアクセスを伴う API には、ブロッキング API とノンブロッキング API の両方を用意しています。

ネットワークアクセスを伴わない API

この API は、デバイス内の処理だけで完結するため、呼び出し元にすぐに制御を戻します。主に、オブジェクトからの値の取得や設定など、ローカルのみで完了する処理を表します。

ネットワークアクセスを伴う API - ブロッキング API

この API では、Kii Cloud に HTTPS リクエストを行い、ネットワークへのアクセスが終わるまで、呼び出し元に制御を返さずに処理をブロックします。

呼び出しによって処理がブロックされるため、この API はモバイルアプリ側で生成した作業スレッドから呼び出すようにします。

実行中に問題が発生した場合は、プラットフォームに応じた方法で API から例外が返ります。Android や Swift では API から例外がスローされます。Objective-C などでは API から例外を表すオブジェクトが返されます。

ネットワークアクセスを伴う API – ノンブロッキング API

この API では、Kii Cloud に HTTPS リクエストを行いますが、API の呼び出しと同時に内部でバックグラウンド処理を開始し、API 自体はすぐに制御を戻します(ネットワークアクセスの間、長時間に渡って処理をブロックしません)。実行結果は、API に渡したコールバックによって通知されます。

この API はユーザーインターフェイススレッドで呼び出します。SDK からのコールバックの呼び出しもユーザーインターフェイススレッドで行われます。

実行中に発生した問題は、基本的にコールバックの引数にある例外オブジェクトによって通知されます。ただし、パラメータチェックなどによる例外は API 呼び出し時にスローされることがあります。

モバイルアプリを実装する場合、ノンブロッキング API を使用すると作業スレッドの生成や管理の手間がなくなり、処理が簡単になります。ただし、Kii Cloud の呼び出しが連続する場合や、他のバックグランド処理と調整しながら Kii Cloud の呼び出しを行いたい場合は、モバイルアプリで管理している作業スレッドにブロッキング API の呼び出しを組み込むと、処理の流れがつかみやすくなります。

いずれの場合も、処理の開始から実行の完了までは一定の時間がかかるため、2 重実行の防止など、モバイルアプリの状態管理にも気をつける必要があります。

サンプルコード

本ガイドのサンプルコードでは、ブロッキング API とノンブロッキング API の双方のサンプルコードを提示しています。

ブロッキング API の一例として、新規ユーザーを登録するためのサンプルコードを以下に挙げます。

Swift 3:

let user = KiiUser(username: "my_username", andPassword: "mypassword")

do{
  try user.performRegistrationSynchronous()
} catch let error as NSError {
  // Handle the error.
  return
}

Objective-C:

NSError *error;
KiiUser *user = [KiiUser userWithUsername:@"my_username"
                              andPassword:@"mypassword"];
[user performRegistrationSynchronous:&error];
if (error != nil) {
  // Handle the error.
}

実際にアプリケーションを開発する際には、アプリケーションが「フリーズ」することを防ぐなどの理由からノンブロッキング API を利用することもできます。Kii iOS SDK は、ノンブロックング API として以下の 2 つの方法を提供しています。

  1. Blocks を使った API
  2. Callbacks を使った API

新規にアプリを作成する場合は Blocks の利用をおすすめします。Callbacks は一部の API ではサポートしていません。

Android SDK とは異なり、iOS SDK ではメインスレッドからブロッキング API を呼び出すこともできます。ただし、アプリケーションのフリーズを防ぐためにも、ノンブロッキング API の利用またはバックグラウンドスレッドからの呼び出しを行ってください。

1. Blocks を使った API

新規ユーザー登録を、Blocks によるノンブロッキング API を用いて実現する例を以下に挙げます。Blocks を使うと、メソッド処理はバックグラウンドスレッドを実行され、処理終了後結果がメインスレッドに返却されます。

Swift 3:

let user = KiiUser(username: "my_username", andPassword: "mypassword")

user.performRegistration { (user :KiiUser?, error : Error?) -> Void in
  if (error != nil) {
    // Handle the error.
  }
}

Objective-C:

KiiUser *user = [KiiUser userWithUsername:@"myusername"
                              andPassword:@"mypassword"];
[user performRegistrationWithBlock:^(KiiUser *user, NSError *error) {
  if (error != nil) {
    // Handle the error.
  }
}];

ノンブロッキング API の利用方法の詳細については、appledoc を参照してください。また Blocks の仕組み自体の詳細については iOS Developer Library を参照してください。

2. Callbacks を使った API

新規ユーザー登録を、Callbacks によるノンブロッキング API を用いて実現する例を以下に挙げます。この場合は、メソッドの処理が完了した際に通知を受けるためのコールバックを定義します。

Swift 3:

class myDelegate : NSObject{
  func userRegistered(user:KiiUser?, error: Error?){
    print("User registered: \(user) withError: \(error)")
    if (error != nil) {
      // Handle the error.
    }
  }
  func test_asynchronous_example(){
    let user = KiiUser(username: "my_username", andPassword: "mypassword")
    user.performRegistration(self, withCallback: Selector(("userRegistered")))
  }
}

Objective-C:

- (void) userRegistered:(KiiUser*)user withError:(NSError*)error {
    NSLog(@"User registered: %@ withError: %@", user, error);

    if (error != nil) {
        // Handle the error.
    }
}

- (void) test_asynchronous_example {
    KiiUser *user = [KiiUser userWithUsername:@"my_username"
                                  andPassword:@"mypassword"];
    [user performRegistration:self
                 withCallback:@selector(userRegistered:withError:)];
}

ノンブロッキング API の利用方法の詳細については、appledoc を参照してください。

ブロッキング API とノンブロッキング API のどちらを使うかは状況次第です。通常、アプリ内から呼び出す際は、ノンブロッキング API を利用すれば容易に機能を実現できます。一方、複数の処理を連続的に実行するような場合は自分でバックグラウンドスレッドを作成して、ブロッキング API を処理の順番どおりに記述した方が見通しがよくなります。