2013/02/03

NSURLRequestのPOSTでTimeoutを機能させる

CocoaのNSURLRequestではタイムアウトを設定することができます。

NSURLRequestでは、initWithURL:cachePolicy:timeoutIntervalによるインスタンス生成時に指定可能ですし、NSMutableURLRequestでは、インスタンス生成後に変更も可能です。

但しiOS5以下の環境では、NSURLRequestインスタンスのタイムアウト値が再設定されてしまう条件が存在します。

その条件とは「インスタンスのタイムアウト値が240秒未満の場合」に「HTTPBodyを設定する」ことであり、これを行うと、タイムアウト値が240秒へ再設定されます。

NSMutableURLRequestインスタンスの場合、timeoutIntervalでタイムアウト値を最設定出来ますが、この場合にも240秒未満へ設定することはできません。

この仕様は古くからコミュニティの間で語られていますが(see:https://devforums.apple.com/message/108292/。要AppleDeveloperアカウント)、残念ながら、Appleのドキュメントへは明記されていないようです。

iOS6ではこの仕様は変更され、タイムアウト値が再設定されてしまうことはありません。ただし、iOS5環境をサポートするアプリケーションでは、アプリケーションで対応する必要があります。

対応策の一つは自身でタイマを設定し、タイムアウトになった時点でコネクションをcancelすることです。

これに基づいたライブラリ「TPTimeoutURLConnection」をgithubへ公開しました

同期通信はNSURLConnectionへのカテゴリとして実装しています。追加メソッドは、次の一つです。
+ sendSynchronousRequest:timeoutInterval:returningResponse:error:

timeoutInterval:引数へ、NSURLRequestで設定したかったタイムアウト値を指定します。例えば次のようにして使います。

ここでは、timeoutInterval:を通じて5秒のタイムアウトを設定しています。

一方非同期通信を行うには、NSURLConnectionを稼働させる際にタイマを起動し、自身が設定したdelegateの適切なメソッドでタイマの廃棄などを行わなければなりません。

そこで、先のライブラリでは雛形となるサンプル実装として、TPURLConnectionクラスと、TPURLConnectionDelegateが同梱されています。特にアプリケーション側の制約がなければ、どちらも継承して使うことが可能です。

例えば次のように利用できるでしょう。

注意すべきことは、NSURLRequestへHTTPBodyを設定した時点でtimeoutIntervalue値が変更されてしまってうことです。そのため、NSURLRequestインスタンス作成時に設定したtimeout値を、そのまま用いることはできません。

なお、このライブラリはiOS6でも動作しますが、iOS6はタイムアウトの制限が撤廃されていますので、利用する理由はありません。

iOS5系をサポートするアプリも少なくなりつつあるとは思いますが、ご意見などお待ちしております。

0 件のコメント:

コメントを投稿