*

iOSプログラミングのキモ(iOS7から使えるようになったマルチタスク機能、NSURLSessionUploadTask の困った現象)

公開日: : Computer Language, FileQ, iOS, iPhone, Objective-C, XCode

FileQIconMini64@2x

このブログでも度々書いてきたFileQ iOS版ですが、今月末に Appleに申請できそうなとこまで来ました、アイコンも作りました。シンプルで ぱっと目に入るデザインにしました。

IMG_1473

iOS7から導入された NSURLSessionをFileQ iOSでも使っていますが、その中の NSURLSessionUploadTask を使っていて少々困ったことがあったので書いておきます、この現象は iPhone5S iOS7.1 で確認しているものです。

コンストラクタである init メソッドの中で まず urlSession_ を初期化します。

// urlSession_ は クラス変数として 定義しておく
urlSession_ = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];

NSURLSessionUploadTaskは、使う直前に初期化します。

    NSDictionary *properties = [[NSMutableDictionary alloc] init];
    [properties setValue:cookieSid forKey:NSHTTPCookieValue];
    [properties setValue:@"fileuploadSID" forKey:NSHTTPCookieName];
    [properties setValue:@"fileq.lisonal.com" forKey:NSHTTPCookieDomain];
    [properties setValue:@"/" forKey:NSHTTPCookiePath];
    
    NSHTTPCookie *cookie = [[NSHTTPCookie alloc] initWithProperties:properties];
    
    NSMutableArray *cookies = [[NSMutableArray alloc]init];
    [cookies addObject:cookie];
    NSDictionary * headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:FILEQ_UPLOAD_URL]];
    [request setHTTPMethod:@"POST"];	//メソッドをPOSTに指定します
    [request setAllHTTPHeaderFields:headers];
    
    NSString *urlStr = [NSString stringWithFormat:@"file://%@", filePath];
    
    // NSURLSessionUploadTask は クラス変数として残しておき バックグラウンド送信直後に開放されてしまうのを防ぐ
    uploadTask_ = [urlSession_ uploadTaskWithRequest:request
                                            fromFile:[NSURL URLWithString:urlStr]
                   ];
    [uploadTask_ resume];

で、問題の箇所ですが

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend

というメソッドを用意しておくと アップロード状況がわかるようになります。

引数で渡ってくる task のプロパティ state を見ると 以下の様な状況がわかります。

typedef NS_ENUM(NSInteger, NSURLSessionTaskState) {
    NSURLSessionTaskStateRunning = 0,                     /* The task is currently being serviced by the session */
    NSURLSessionTaskStateSuspended = 1,
    NSURLSessionTaskStateCanceling = 2,                   /* The task has been told to cancel.  The session will receive a URLSession:task:didCompleteWithError: message. */
    NSURLSessionTaskStateCompleted = 3,                   /* The task has completed and the session will receive no more delegate notifications */
} NS_ENUM_AVAILABLE(10_9, 7_0);

本来は

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend

が 呼ばれるときは state の値は NSURLSessionTaskStateRunning のはずなのですが
しばらくすると 何故か NSURLSessionTaskStateCompleted で返って来ます、実際 アップロード処理は終わっています。
なのに 相変わらず 上記メソッドが呼ばれ続け 一向にアップロードが終わってないふうになってしまう という現象です。

いろいろ調べましたが 根本的解決方法が見つかりませんでした。
仕方なく アップロード処理はちゃんと終わっていたので task.state が NSURLSessionTaskStateCompleted になったら 強制的にsessionを終わらせるようにしました。

    if(uploadTask_.state == NSURLSessionTaskStateCompleted && oldStatus_ != uploadTask_.state){ // 何故かこんな状態になることがある
        [self URLSession:session task:task didCompleteWithError:nil]; // 本来はiOSから呼んでくれる delegate メソッドを自分で呼ぶ
        [urlSession_ finishTasksAndInvalidate]; // urlSession にあるタスクを終わらせる
        [urlSession_ invalidateAndCancel]; // urlSession を無効化する
        
        // 新しい urlSession_ を作る
        NSString *fileSendId = [NSString stringWithFormat:@"%@_%d", FILEQ_BACKGROUND_FILE_SEND_ID, idCounter_]; idCounter_++;
        NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfiguration:fileSendId];
        urlSession_ = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
        oldStatus_ = uploadTask_.state;
    }

釈然としない現象ですが とりあえず上記の処置でアプリは動くので、このまま行こうと思います。
ちなみに NSURLSessionUploadTask の反対 NSURLSessionDownloadTask では このような現象は出ていません。

実際のアップロード処理はiOSの中なので なかなか追いかけ切れません、今後のバージョンアップで解決して欲しいところです。

どなたか 解決方法をご存知であれば コメントに書いてください。

関連記事

iOSプログラミングのキモ(行き当たりばったりなプログラミングでも、何とか形にするために守っていること その2)

先週に引き続き、今週も文字中心のエントリーです、今回は 下記3つのことを書いていきます。 M

記事を読む

iOSプログラミングのキモ(複雑な画面を複数のViewControllerで制御する その2)

先週は、複数のViewControllerで1つの画面を構成する話のうち、親ViewControll

記事を読む

iOSプログラミングのキモ(2:ソースコード概説 )主要なObjective-Cソース・ファイル一覧

QTubeの主要Objective-Cのソース一覧です。 iOSでは アプリを作る場合 Objec

記事を読む

iOSプログラミングのキモ(iOS7から使えるようになったマルチタスク機能、NSURLSessionはこう使え!)

今日はQTubeのソースに関する話題ではなく、現在開発中のアプリで使っているNSURLSession

記事を読む

iOSプログラミングのキモ(AppDelegate説明 NSUserDefaultsに設定情報を格納する )

QTubeは、YouTubeを閲覧するときに 国別コードを設定しています。国別コードは iOSに設定

記事を読む

iOSプログラミングのキモ(MainViewController説明)

個別の画面のコードについて解説を進めていきます。最初は起動直後の画面であるMainViewContr

記事を読む

iOSプログラミングのキモ(拡張子がpchというファイルの役目)

XCodeで プロジェクトを作成すると、-prefix.pch というファイルができています。このフ

記事を読む

iPhoneが7GBの転送制限に引っかかりそうになって Nexus7(2013)LTE版のテザリング機能が大活躍

皆さんは スマホを使ってて、転送制限に引っかかったことはありますか?私はあります(笑) 最

記事を読む

iOSプログラミングのキモ(Delegate iOSプログラミングで避けて通れないしくみ)

Delegate(委任)の考え方を説明します。iOSのプログラミングでは このDelegateが頻繁

記事を読む

iOSプログラミングのキモ

このブログでは、実際に弊社が公開しているアプリのソースコードを使って、iOSプログラミングのキモを解

記事を読む

Comment

  1. 平塚乃一 より:

    mixi:ダイちゃん

    いつも訪問有難うございます。
    iOSプログラミングのプロなんですね!
    応援させて下さい。
    宜しくお願いします。

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

FileQ Hosting 月額99円 容量1GB


サイト管理 Mezzanine
Django上で動くCMS Mezzanine 用のモジュールを作ってみる その1

Django上で動くCMS Mezzanine上で動く、モジュールを作

ホーム Mezzanine
Django上で動くCMS Mezzanine を インストールする MacOSX Yesemite 編

Mezzanineは Django WEBフレームワーク上で動くCMS

EclipseにGWT(Google Web Toolkit) Plugin for Eclipseを入れようとしてハマった

最近PHPでちょっとした業務システムを作りました。業務システムの特徴と

ブログを半年やった成果を Google Analytics から眺める

今年の1月からブログを書き始め、そろそろ半年が経とうとしています。

母校で特別 講義をやってきました。

少し 間が空いてしまいました(^_^;) ちょっと前になりますが

→もっと見る

mautic is open source marketing automation
PAGE TOP ↑