AZSocketIOを使ってiOSアプリからnode.js+Socket.IOと双方向通信する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

前回iOSアプリからnode.js+Socket.IOと双方向通信する | Developers.IOではsocket.IO-objcを紹介しました。このライブラリは非常に優秀なのですが、接続に失敗した場合に別のトランスポートへの再接続処理を自動でやってくれませんでした(知ってたら教えてください!)。

で、今回紹介するAZSocketIOはその再接続処理も行ってくれるなんとも便利なライブラリです。AZSocketIOは使い方も非常に簡単です。というわけで早速使ってみませう。

サーバ側の実装

さて、サーバ側は前回に引き続き弊社うえじゅん氏が公開しているNode + Socket.IO で簡単なチャットアプリの作成 | Developers.IOで作ったチャットアプリを使用しますので、先にチャットアプリを作っちゃっちゃってください。

プロジェクトの準備

チャットアプリの準備が終わったら、早速iOSアプリ側の準備をしましょう。ここからは以下の環境を前提に説明します。

  • OS X 10.9
  • Xcode 5.0.2
  • iOS SDK 7.0

さて、テキトーにプロジェクトを作りましょう。ここではSingle View ApplicationAZSocketIOという名前でプロジェクトを作成しました。

AZSocketIOをCocoaPodsでインストール

プロジェクトディレクトリ配下にPodfileを作成して、以下のように記述してください。

pod 'AZSocketIO'

pod installを実行すると、勝手にSocketRocketAFNetworkingがインストールされます。ちょっと残念なのが、AFNetworking 2.xには対応していないため、1.3.xがインストールされてしまいます。。。

これで、インストール完了です。

早速つないでみる

ViewController.mを開き、以下のように記述してみましょう。

#import "ViewController.h"

#import <AZSocketIO/AZSocketIO.h>

@interface ViewController ()

// Socket.IOクライアント
@property (nonatomic, strong) AZSocketIO *socketIO;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // ホストとポート番号を指定してAZSocketIOインスタンス生成
    self.socketIO = [[AZSocketIO alloc] initWithHost:@"localhost"
                                             andPort:@"3000"
                                              secure:NO];

    // メッセージを受信した時に実行されるBlocks
    [self.socketIO setMessageRecievedBlock:^(id data) {
        NSLog(@"data: %@", data);
    }];

    // イベントを受信したときに実行されるBlocks
    [self.socketIO setEventRecievedBlock:^(NSString *eventName, id data) {
        NSLog(@"eventName: %@, data: %@", eventName, data);
    }];

    // エラーを受信したときに実行されるBlocks
    [self.socketIO setErrorBlock:^(NSError *error) {
        NSLog(@"error: %@", error);
    }];

    // 切断されたときに実行されるBlocks
    [self.socketIO setDisconnectedBlock:^{
        NSLog(@"Disconnected!");
    }];

    // 接続開始
    [self.socketIO connectWithSuccess:^{
        NSLog(@"Success connecting!");
    } andFailure:^(NSError *error) {
        NSLog(@"Failure connecting. error: %@", error);
    }];
}

@end

たったこれだけです!簡単ですね。すごーく大まかな流れは、

  1. AZSocketIOインスタンスの作成してプロパティに保持(メソッド抜けたらなくなっちゃうのでw)
  2. 処理したいコールバックに処理を書く
  3. 接続開始!

と非常にシンプルですね。

サーバを起動しておきつつデバッグ実行したらブラウザからメッセージを送信してみましょう。すると、以下のようにXcodeのコンソールにログが出力されます。

ios-azsocketio-2

AZSocketIOインスタンスの作成

さて、AZSocketIOインスタンスの作成には、以下のメソッドが用意されています。

  • - (id)initWithHost:(NSString *)host andPort:(NSString *)port secure:(BOOL)secureConnections
  • - (id)initWithHost:(NSString *)host andPort:(NSString *)port secure:(BOOL)secureConnections withNamespace:(NSString *)endpoint

説明は不要ですねw

hostにはホスト名(http://とかは無し)、portは文字列で指定するってことぐらいでしょうか?基本的にこのインスタンスを使ってサーバとのやりとりを行うようになります。なので、生成したインスタンスはどっかで保持しておきましょう。

もろもろのタイミングで呼ばれるBlocksたち

接続を開始してからは以下の4つのBlocksが適宜呼ばれます。

messageRecievedBlock

メッセージを受信した時に実行されるBlocks
eventRecievedBlock

イベントを受信したときに実行されるBlocks
disconnectedBlock

エ切断されたときに実行されるBlocks
errorBlock

エラーを受信したときに実行されるBlocks

これらのBlocksを設定するには、それぞれ以下のメソッドを使用します。

  • - (void)setMessageRecievedBlock:(void (^)(id data))messageRecievedBlock
  • - (void)setEventRecievedBlock:(void (^)(NSString *eventName, id data))eventRecievedBlock
  • - (void)setDisconnectedBlock:(void (^)())disconnectedBlock
  • - (void)setErrorBlock:(void (^)(NSError *error))errorBlock

イベント受信時の処理に関してはイベント毎にコールバック用のBlocksを設定できます。その場合は- (void)addCallbackForEventName:(NSString *)name callback:(void (^)(NSString *eventName, id data))blockメソッドを使用します。

// message:receiveイベント受信時の処理
[self.socketIO addCallbackForEventName:@"message:receive" callback:^(NSString *eventName, id data) {
    NSLog(@"eventName: %@, data: %@", eventName, data);
}];

尚、- (void)addCallbackForEventName:(NSString *)name callback:(void (^)(NSString *eventName, id data))blockメソッドで追加されたイベントはmessageRecievedBlockでは処理されないようになります。

ここで登録したコールバック用のBlocksは、- (BOOL)removeCallbackForEvent:(NSString *)name callback:(void (^)(NSString *eventName, id data))blockメソッドや- (NSInteger)removeCallbacksForEvent:(NSString *)nameメソッドで削除できます。

接続と切断

準備ができたら接続を開始します。

接続の開始と切断は非常に簡単です。開始するときは- (void)connectWithSuccess:(void (^)())success andFailure:(void (^)(NSError *error))failureメソッドを、切断するときは- (void)disconnectメソッドを実行するだけです。

// 接続開始
[self.socketIO connectWithSuccess:^{
    NSLog(@"Success connecting!");
} andFailure:^(NSError *error) {
    NSLog(@"Failure connecting. error: %@", error);
}];

// 切断
[self.socketIO disconnect];

接続完了時は成功・失敗のときにそれぞれ設定したBlocksが実行され、切断した場合はdisconnectedBlockが実行されます。

データの送信

データの送信の話に入る前に、StoryboardからViewControllerにテキストフィールドと送信ボタンを配置してそれぞれアウトレットとアクションを定義しておきましょう。

ios-azsocketio-1

データを送信するためには、以下のように記述します。

- (IBAction)sendEventButtonTapped:(id)sender
{
    NSString *message = self.textField.text;

    // テキストフィールドが入力されていたら、その内容をmessage:sendイベントで送信する
    if (message && message.length > 0) {
        [self.socketIO emit:@"message:send" args:@{@"message" : message} error:NULL];
    }
}

AZSocketIOでは送信系のメソッドとして以下のメソッドが用意されています。

  • send系
    • - (BOOL)send:(id)data error:(NSError * __autoreleasing *)error
    • - (BOOL)send:(id)data error:(NSError *__autoreleasing *)error ackWithArgs:(void (^)(NSArray *data))callback
    • - (BOOL)send:(id)data error:(NSError *__autoreleasing *)error ack:(void (^)())callback
  • emit系
    • - (BOOL)emit:(NSString *)name args:(id)args error:(NSError * __autoreleasing *)error
    • - (BOOL)emit:(NSString *)name args:(id)args error:(NSError *__autoreleasing *)error ackWithArgs:(void (^)(NSArray *data))callback
    • - (BOOL)emit:(NSString *)name args:(id)args error:(NSError *__autoreleasing *)error ack:(void (^)())callback

これまた簡単!

設定できる値

プロパティ 説明
reconnect BOOL 再接続処理を実行するか。デフォルトはYES。
reconnectionDelay NSTimeInterval 初回の再接続処理を何秒後に実行するか設定できる。デフォルトは0.5。
reconnectionLimit NSTimeInterval 再接続処理の遅延秒数の上限を指定できる。デフォルトはMAX_FLOAT。
maxReconnectionAttempts NSUInteger 再接続処理の最大試行回数。デフォルトは10。

これらの設定値は以下のように指定します。

// ホストとポート番号を指定してAZSocketIOインスタンス生成
self.socketIO = [[AZSocketIO alloc] initWithHost:@"localhost"
                                         andPort:@"3000"
                                          secure:NO];

self.socketIO.reconnect = YES;
self.socketIO.reconnectionDelay = 1.0;
self.socketIO.reconnectionLimit = 2048.0;
self.socketIO.maxReconnectionAttempts = 5;

AZSocketIOでは、接続に失敗した場合、reconnectがYESであれば再接続を試みます。再接続処理に失敗すると、以降はreconnectionDelayを2倍に設定しなおして再接続処理を行います。なので、デフォルトだとreconnectionDelayは0.5、1.0、2.0、4.0、8.0、・・・と増えていきます。

まとめ

ご覧の通り、使い方は非常に簡単ですね!ネックなのは、前述した通りAFNetworking2.xに対応していない点ですね。。。まぁこの点を加味しても非常に有用なライブラリだと思いますので、是非使ってみてください!