swift - 从 Cocoa 中的 C api 调用 Swift 闭包时出现访问错误

标签 swift closures interop function-pointers

我正在尝试在 macOS 上的 Swift 中实现“带进度的文件复制”。 经过大量搜索,我刚刚找到 rustle's implement in Objective-C . 它工作得很好。 但我希望它“swift ”。 我尝试了一些简化的代码:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    var copyfileCallback: copyfile_callback_t = {(what, stage, state, sourcePath, destPath, context) -> Int32 in
        return COPYFILE_CONTINUE
    }

    @IBOutlet weak var window: NSWindow!

    func applicationDidFinishLaunching(_ aNotification: Notification) {

        let src = NSURL(fileURLWithPath: "Source_File_Path").fileSystemRepresentation
        let dst = NSURL(fileURLWithPath: "Destination_File_Path").fileSystemRepresentation
        let flag: copyfile_flags_t = UInt32(COPYFILE_ALL)

        let state = copyfile_state_alloc()

        // If I implement this, the copyfile() method will complain "EXC_BAD_ACCESS(code=2..." error
        copyfile_state_set(state, UInt32(COPYFILE_STATE_STATUS_CB), &copyfileCallback)

        copyfile(src, dst, state, flag)
    }
}

基本函数 copyfile() 工作正常。但是,如果我通过向 copyfile_state_set() 提供一个 copyfileCallback 闭包指针来实现回调函数,那么 copyfile() 只会提示“Bad_Access.. ”。 我想也许闭包是在 C api 尝试访问它之前发布的。 但我不知道如何解决这个问题...... 任何线索将不胜感激。

最佳答案

错误在这里:

copyfile_state_set(state, UInt32(COPYFILE_STATE_STATUS_CB), &copyfileCallback)

因为是将 copyfileCallback 变量的地址 传递给函数,而不是函数指针本身。在 C 中,您可以将任意函数作为 void * 参数传递。在 Swift 中,您必须显式地将函数转换为指针:

let state = copyfile_state_alloc()
copyfile_state_set(state, UInt32(COPYFILE_STATE_STATUS_CB),
                   unsafeBitCast(copyfileCallback, to: UnsafeRawPointer.self))

并且不要忘记在复制操作之后最终释放内存:

copyfile_state_free(state)

备注:在Swift中推荐使用(值叠加类型)URL代替NSURL:

let srcURL = URL(fileURLWithPath: "Source_File_Path")
let destURL = URL(fileURLWithPath: "Destination_File_Path")

let result = srcURL.withUnsafeFileSystemRepresentation { srcFile in
    destURL.withUnsafeFileSystemRepresentation { destFile in
        copyfile(srcFile, destFile, state, flag)
    }
}

关于swift - 从 Cocoa 中的 C api 调用 Swift 闭包时出现访问错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55218788/

相关文章:

.net - 如何覆盖 GetWebResponse

xcode - setImageWithUrl 从 Parse.com 到 UICollectionView

c# - 从 C header 自动创建 C# 包装器?

ios - cosmicmind Material swift MenuView 不关闭

iphone - 将 block 闭包存储为 IBAction

使用 eval 的 javascript 调试功能

ios - Swift 中的闭包数组

c# - 将 C++ 类编码(marshal)到 C#

ios - 0.1 以下的 UIProgressView 值无法正确显示

swift - 在 Swift 3 中打印