【发布时间】:2017-01-25 14:37:05
【问题描述】:
因此,与recently posted question 类似,我在将 Amazon 的 AWS Obj-C 库与我的 Swift 应用程序集成时遇到了问题。我有一个NSOperation,它使用他们的Transfer Utility library 处理文件上传到S3,其中包括对后台文件传输的支持。最近发布了我们的应用程序后,当应用程序回到前台时,我发现代码中出现了一些崩溃,这些崩溃会重新连接进度处理程序。代码改编自their Obj-C example:
- (void)viewDidLoad {
[super viewDidLoad];
...
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.
}];
}
到我的 Swift 版本,它在尝试取消引用 newProgressPointer 时崩溃并出现 EXC_BAD_ACCESS KERN_INVALID_ADDRESS:
// Swift 2.3
class AttachmentQueue: NSOperationQueue {
...
/**
Recreates `UploadOperation` instances for any that were backgrounded by the user leaving the
app.
*/
func addBackgroundedOperations() {
let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
transferUtility.enumerateToAssignBlocksForUploadTask({ (task, progress, completion) -> Void in
guard let operation = UploadOperation(task: task, oldProgressPointer: progress, oldCompletionPointer: completion) else { return }
self.addOperation(operation)
}, downloadTask: nil)
}
}
/// An `UploadOperation` is an `NSOperation` that is responsible for uploading an attachment asset
/// file (photo or video) to Amazon S3. It leans on `AWSS3TransferUtility` to get the actual
/// uploading done.
class UploadOperation: AttachmentOperation {
...
/// An `AutoreleasingUnsafeMutablePointer` to the upload progress handler block.
typealias UploadProgressPointer = AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityTask, NSProgress) -> Void)?>
/// An `AutoreleasingUnsafeMutablePointer` to the upload completion handler block.
typealias UploadCompletionPointer = AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityUploadTask, NSError?) -> Void)?>
/**
A convenience initializer to be used to re-constitute an `AWSS3TransferUtility` upload task that
has been moved to the background. It should be called from `.enumerateToAssignBlocksForUploadTask()`
when the app comes back to the foreground and is responsible for re-hooking-up its progress and
completion handlers.
- parameter task: The `AWSS3TransferUtilityTask` that needs re-hooking-up.
- parameter oldProgressPointer: An `AutoreleasingUnsafeMutablePointer` to the original progress handler.
- parameter oldCompletionPointer: An `AutoreleasingUnsafeMutablePointer` to the original completion handler.
*/
convenience init?(task: AWSS3TransferUtilityUploadTask, oldProgressPointer: UploadProgressPointer, oldCompletionPointer: UploadCompletionPointer) {
self.init(attachment: nil) // Actual implementation finds attachment record
// Re-connect progress handler
var progressBlock: AWSS3TransferUtilityProgressBlock = self.uploadProgressHandler
let newProgressPointer = UploadProgressPointer(&progressBlock)
print("newProgressPointer", newProgressPointer)
print("newProgressPointer.memory", newProgressPointer.memory) // Throws EXC_BAD_ACCESS KERN_INVALID_ADDRESS
oldProgressPointer.memory = newProgressPointer.memory
// Re-connect completion handler
var completionBlock: AWSS3TransferUtilityUploadCompletionHandlerBlock = self.uploadCompletionHandler
let newCompletionPointer = UploadCompletionPointer(&completionBlock)
oldCompletionPointer.memory = newCompletionPointer.memory
}
/**
Handles file upload progress. `AWSS3TransferUtility` calls this repeatedly while the file is
uploading.
- parameter task: The `AWSS3TransferUtilityTask` for the current upload.
- parameter progress: The `NSProgress` object for the current upload.
*/
private func uploadProgressHandler(task: AWSS3TransferUtilityTask, progress: NSProgress) {
// We copy the `completedUnitCount` to operation but it would be nicer if we could just
// reference the one passed to us instead of having two separate instances
self.progress.completedUnitCount = progress.completedUnitCount
// Calculate file transfer rate using an exponential moving average, as per https://stackoverflow.com/a/3841706/171144
let lastRate = self.transferRate
let averageRate = Double(progress.completedUnitCount) / (NSDate.timeIntervalSinceReferenceDate() - self.uploadStartedAt!)
self.transferRate = self.smoothingFactor * lastRate + (1 - self.smoothingFactor) * averageRate;
progress.setUserInfoObject(self.transferRate, forKey: NSProgressThroughputKey)
}
/**
Handles file upload completion. `AWSS3TransferUtility` calls this when the file has finished
uploading or is aborted due to an error.
- parameter task: The `AWSS3TransferUtilityTask` for the current upload.
- parameter error: An instance of `NSError` if the upload failed.
*/
private func uploadCompletionHandler(task: AWSS3TransferUtilityUploadTask, error: NSError?) {
...
}
...
}
为什么指针memory引用创建后直接无效?
作为 iOS 开发的新手并且没有使用 Obj-C(或其他非内存管理语言)的实际经验,我有点迷茫。如果有人能提供一些启示,将不胜感激。
编辑:
enumerateToAssignBlocksForUploadTask(…) 的 Swift 方法签名
/**
Assigns progress feedback and completion handler blocks. This method should be called when the app was suspended while the transfer is still happening.
@param uploadBlocksAssigner The block for assigning the upload pregree feedback and completion handler blocks.
@param downloadBlocksAssigner The block for assigning the download pregree feedback and completion handler blocks.
*/
public func enumerateToAssignBlocksForUploadTask(uploadBlocksAssigner: ((AWSS3TransferUtilityUploadTask, AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityTask, NSProgress) -> Void)?>, AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityUploadTask, NSError?) -> Void)?>) -> Void)?, downloadTask downloadBlocksAssigner: ((AWSS3TransferUtilityDownloadTask, AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityTask, NSProgress) -> Void)?>, AutoreleasingUnsafeMutablePointer<(@convention(block) (AWSS3TransferUtilityDownloadTask, NSURL?, NSData?, NSError?) -> Void)?>) -> Void)?)
【问题讨论】:
标签: ios objective-c swift