7

Official AWS docs contains the following objective-c code

 AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
[transferUtility
 enumerateToAssignBlocksForUploadTask:^(AWSS3TransferUtilityUploadTask *uploadTask, __autoreleasing AWSS3TransferUtilityUploadProgressBlock *uploadProgressBlockReference, __autoreleasing AWSS3TransferUtilityUploadCompletionHandlerBlock *completionHandlerReference) {
     NSLog(@"%lu", (unsigned long)uploadTask.taskIdentifier);

     // Use `uploadTask.taskIdentifier` to determine what blocks to assign.

     *uploadProgressBlockReference = // Reassign your progress feedback block.
     *completionHandlerReference = // Reassign your completion handler.
 }
 downloadTask:^(AWSS3TransferUtilityDownloadTask *downloadTask, __autoreleasing AWSS3TransferUtilityDownloadProgressBlock *downloadProgressBlockReference, __autoreleasing AWSS3TransferUtilityDownloadCompletionHandlerBlock *completionHandlerReference) {
     NSLog(@"%lu", (unsigned long)downloadTask.taskIdentifier);

     // Use `downloadTask.taskIdentifier` to determine what blocks to assign.

     *downloadProgressBlockReference =  // Reassign your progress feedback block.
     *completionHandlerReference = // Reassign your completion handler.
 }];

I tried converting it into Swift 3 (upload task only)

transferUtility.enumerateToAssignBlocks(forUploadTask:
        {

            let progressPointer = AutoreleasingUnsafeMutablePointer<AWSS3TransferUtilityUploadProgressBlock?>(&uploadProgressBlock)
            let completionPointer = AutoreleasingUnsafeMutablePointer<AWSS3TransferUtilityUploadCompletionHandlerBlock?>(&completionBlock)

            progress = progressPointer
            completion = completionPointer

    }
        , downloadTask: nil)

But Xcode throws the following error

Cannot convert value of type ()->() to expected argument type[...]

Anyone got it working in Swift 3? Probably method signatures have changed

EDIT:

I applied @donkon answer:

        transferUtility.enumerateToAssignBlocks(forUploadTask: { (uploadTask:AWSS3TransferUtilityUploadTask, progress:AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityTask, Progress) -> Void)?>?, error: AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityUploadTask, Error?) -> Void)?>?) in

                        let progressPointer = AutoreleasingUnsafeMutablePointer<AWSS3TransferUtilityProgressBlock?>(&self.progressBlock)
                        let completionPointer = AutoreleasingUnsafeMutablePointer<AWSS3TransferUtilityUploadCompletionHandlerBlock?>(&self.completionHandler)
        //

                        progress = progressPointer

                        completion = completionPointer


    }, downloadTask: nil)

now Xcode tells that both progress and completion are let values and cannot be changed.

theDC
  • 6,364
  • 10
  • 56
  • 98

2 Answers2

3

The method you are trying to use has arguments that are functions. These functions in the SDK are written in Objective-C. So you should use @convention(block) to indicate that they are Objective-C compatible block references.

AWSS3TransferUtility.default().enumerateToAssignBlocks(forUploadTask: { (uploadTask:AWSS3TransferUtilityUploadTask, uploadProgressBlockReference:AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityTask, Progress) -> Void)?>?, completionHandlerReference: AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityUploadTask, Error?) -> Void)?>?) in
    print("Hello, world")

    uploadProgressBlockReference?.pointee = {(task:AWSS3TransferUtilityTask, progress:Progress) -> Void in
        print("Fraction completed:  \(progress.fractionCompleted)")
    }
}, downloadTask: nil)
donkon
  • 909
  • 9
  • 23
  • I took it from here: https://github.com/awslabs/aws-sdk-ios-samples/issues/28 Could you relate to it? Also have you tried it before, is this suffcient to make it work even when app was killed by the system? – theDC Jan 24 '17 at 22:15
  • I just tried it. The transfer will not go through if the app is killed. Only if the app is in the background will the transfer continue. – donkon Jan 24 '17 at 22:26
  • well these blocks are used to get feedback - completion handler and progress even when the app is killed by the system(not by the user) - did it work that way? – theDC Jan 24 '17 at 22:29
  • If the app is killed, there won't be any feedback, where do you expect the feedback to go to if your app is killed? – donkon Jan 24 '17 at 22:38
  • App should be relaunched, this is how it's supposed to work i guess. Otherwise, what for we would use these blocks, my app works nice in background without them – theDC Jan 24 '17 at 22:40
  • Misnamed one of the parameters. I updated the answer to have the `completionHandlerReference` – donkon Jan 24 '17 at 23:26
  • Thanks, will check it out tomorrow morning and get back with feedback. Could you relate to my previous comment about background capabilities? Correct me If I'm wrong but these blocks are used when system kills the app, these enables the feature to get completion and progress in self relaunched app when the upload is done. Note that the upload is handled by system - It works even when you force kill the app – theDC Jan 24 '17 at 23:28
0

It's not worth fighting that that method in swift, just go around it. I'm pretty sure this accomplishes the same thing doing this.

 func handleForeground() {
    if let multiPartUploadTasks = self.transferUtility.getMultiPartUploadTasks().result, let uploads = multiPartUploadTasks as? [AWSS3TransferUtilityMultiPartUploadTask] {
        for upload in uploads {
            upload.setProgressBlock(self.progressBlock)
            upload.setCompletionHandler(self.completionBlock)
        }
    }
}
Ryan Romanchuk
  • 10,819
  • 6
  • 37
  • 41