Open2

AWS SDK iOSのS3アップロード部分についてコードを読む

yimajoyimajo

はじめに

OSSであるAWS SDK iOSのS3アップロード部分についてコードを読む

https://github.com/aws-amplify/aws-sdk-ios/tree/main/AWSS3

AWS S3 SDK登場人物

  • タスクに関わるBoltsから移行されたやつら
    • AWSTask<__covariant ResultType> : NSObject
      • Future/Promise的なやつ
      • async/awaitのawaitもできる
    • AWSExecutor : NSObject
      • クロージャを実行するやつ
      • Grand Central Dispatcherをラップしたようなイメージ
    • AWSCancellationToken : NSObject
      • キャンセルするやつ
      • 作成し、
  • アップロードに関するやつ
    • AWSS3TransferUtilityUploadTask : AWSS3TransferUtilityTask
      • completionHandlerやprogressHandlerをセットできる
        • AWSTaskからできるのでこれを直接やらなくてもいい
    • AWSS3TransferUtilityTask: NSObject
      • こいつのデータを永続化したら良さそう
      • 永続化必須
        • NSString *transferID;
      • その他 AWSS3TransferUtilityTask ができること
        • キャンセル
        • completionHandlerやprogressHandler
yimajoyimajo

interceptApplication

  • バックグランド通信成功時にアプリがバックグラウンドから復帰させられるための処理
    • 復帰してファイル出力したりDB書き込みしたりする
      • 復帰させられるというのはオンメモリ上では生きてる(=終了してるわけじゃない)
        • そもそも終了してたらバックグラウンド通信も終了している

https://github.com/aws-amplify/aws-sdk-ios/blob/2ce94a7fda175ed6ffd86c993b0ace219b926ac2/AWSS3/AWSS3TransferUtility.m#L2000-L2019

何をやってるの?

  • idが渡されるのでそのidを持ってるかチェック
    • completionHandlerを保持
+ (void)interceptApplication:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier
           completionHandler:(void (^)(void))completionHandler {
    AWSDDLogDebug(@"interceptApplication called for URLSession [%@]", identifier);
    
    // For the default service client
    if ([identifier isEqualToString:_defaultS3TransferUtility.sessionIdentifier]) {
        _defaultS3TransferUtility.backgroundURLSessionCompletionHandler = completionHandler;
    }
    
    // For the SDK managed service clients
    for (NSString *key in [_serviceClients allKeys]) {
        AWSS3TransferUtility *transferUtility = [_serviceClients objectForKey:key];
        if ([identifier isEqualToString:transferUtility.sessionIdentifier]) {
            AWSDDLogDebug(@"Setting completion handler for urlSession [%@]", identifier);
            
            transferUtility.backgroundURLSessionCompletionHandler = completionHandler;
        }
    }
}

ここでは保持してるだけだが、このcompletionHandlerを終了した際に呼び出すとNSURLSessionのDelegateが動作するらしい。

https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_in_the_background

(記述はバックグラウンドダウンロードなのでDelegateはダウンロードの urlSessionDidFinishEvents(forBackgroundURLSession:)が動作してる)

When all events have been delivered, the system calls the urlSessionDidFinishEvents(forBackgroundURLSession:) method of URLSessionDelegate. At this point, fetch the backgroundCompletionHandler stored by the app delegate in Listing 3 and execute it. Listing 4 shows this process.
Note that because urlSessionDidFinishEvents(forBackgroundURLSession:) may be called on a secondary queue, it needs to explicitly execute the handler (which was received from a UIKit method) on the main queue.

つまり、このcompletionHandlerはアプリ内のDelegateに終了を通知するため。なぜそうやるのか想像するに

  • バックグラウンド通信の終了はAppDelegateに通知
    • AppDelegateからアプリ内のNSURLSesssionに通知する手段としてcompletionHandlerを使う

ということだろう(想像です)。