gpt4 book ai didi

ios - 为什么我刚创建的指针抛出 KERN_INVALID_ADDRESS?

转载 作者:可可西里 更新时间:2023-11-01 02:08:31 25 4
gpt4 key购买 nike

所以与此类似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)?)

最佳答案

我认为您不应该需要这些指针中的大部分(或任何)。看看 Swift example code from AWS看看它是否不符合您的要求。

以您现有的方式创建指针在 Swift 中并不安全。这可能比您需要的信息多得多(您不必如此努力地工作),但可能会发生这种情况(在这种情况下,这种解释并不完全正确,但这是可能发生的事情,所以值得了解):

  • 您创建一个指向本地(堆栈)变量的指针 progressBlock
  • 系统发现 progressBlock 不再在范围内的任何其他地方访问。
  • 在允许的情况下,ARC 会销毁 progressBlock
  • 您不安全地访问指向已销毁变量的指针,然后崩溃。

我说这感觉不对,因为还有对闭包的第二个引用无论如何都应该使闭包保持事件状态,但通常,以这种方式使用构造函数创建指针是非常危险的。

(这可能会崩溃,因为您无法打印 @convention(block) 闭包;我从未尝试过这样做。这不是很正常尝试打印的东西。)

无论如何,如果您确实需要做这种事情(而且我认为您不需要),您需要按照以下方式进行:

withUnsafeMutablePointer(to: self.uploadProgressHandler) { newProgressPointer in 
... newProgressPointer is safe to use in this block ...
}

但通常,如果您正在转换 ObjC 代码(不是纯 C,而只是 ObjC),并且发现您必须创建很多 Unsafe 对象,您可能正在走走错了路。大多数 ObjC 事物都可以很好地桥接到 Swift,而无需 Unsafe

关于ios - 为什么我刚创建的指针抛出 KERN_INVALID_ADDRESS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41854286/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com