如何使用实例方法作为只接受 func 或文字闭包的函数的回调 [英] How to use instance method as callback for function which takes only func or literal closure

查看:17
本文介绍了如何使用实例方法作为只接受 func 或文字闭包的函数的回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在ViewController.swift"中,我正在创建这个回调:

In "ViewController.swift" I am creating this callback:

func callback(cf:CFNotificationCenter!, 
    ump:UnsafeMutablePointer<Void>, 
    cfs:CFString!, 
    up:UnsafePointer<Void>, 
    cfd:CFDictionary!) -> Void {

}

使用这个观察者:

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), 
    nil, 
    self.callback, 
    "myMESSage", 
    nil, 
    CFNotificationSuspensionBehavior.DeliverImmediately)

导致此编译器错误:

C 函数指针只能由对‘func’或文字闭包的引用构成"

"A C function pointer can only be formed from a reference to a 'func' or a literal closure"

推荐答案

回调是一个指向 C 函数的指针,在 Swift 中可以通过只有一个全局函数或一个闭包(不捕获任何状态),但不是实例方法.

The callback is a pointer to a C function, and in Swift you can pass only a global function or a closure (which does not capture any state), but not an instance method.

所以这确实有效:

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
        nil,
        { (_, observer, name, _, _) in
            print("received notification: (name)")
        },
        "myMessage",
        nil,
        .DeliverImmediately)

但是由于闭包无法捕获上下文,因此您无法直接引用 self 及其属性和实例方法.例如,您不能添加

But since the closure cannot capture context, you have no direct reference to self and its properties and instance methods. For example, you cannot add

self.label.stringValue = "got it"
// error: a C function pointer cannot be formed from a closure that captures context

在通知到达时在闭包内更新 UI.

inside the closure to update the UI when a notification arrived.

有一个解决方案,但由于它有点复杂Swift 的严格类型系统.类似于 Swift 2 - UnsafeMutablePointer到对象,您可以将指针转换为self 指向空指针,将其作为 observer 参数传递到注册,并将其转换回对象指针回调.

There is a solution, but it is a little bit complicated due to Swift's strict type system. Similarly as in Swift 2 - UnsafeMutablePointer<Void> to object, you can convert the pointer to self to a void pointer, pass that as the observer parameter to the registration, and convert it back to an object pointer in the callback.

class YourClass { 

    func callback(name : String) {
        print("received notification: (name)")
    }

    func registerObserver() {

        // Void pointer to `self`:
        let observer = UnsafePointer<Void>(Unmanaged.passUnretained(self).toOpaque())

        CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
            observer,
            { (_, observer, name, _, _) -> Void in

                // Extract pointer to `self` from void pointer:
                let mySelf = Unmanaged<YourClass>.fromOpaque(
                        COpaquePointer(observer)).takeUnretainedValue()
                // Call instance method:
                mySelf.callback(name as String)
            },
            "myMessage",
            nil,
            .DeliverImmediately)
    }

    // ...
}

闭包充当实例方法的蹦床".

The closure acts as a "trampoline" to the instance method.

指针是一个未保留的引用,因此您必须确保在对象被释放之前移除观察者.

The pointer is an unretained reference, therefore you must ensure that the observer is removed before the object is deallocated.

Swift 3 更新:

class YourClass {

    func callback(_ name : String) {
        print("received notification: (name)")
    }

    func registerObserver() {

        // Void pointer to `self`:
        let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())

        CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
            observer,
            { (_, observer, name, _, _) -> Void in
                if let observer = observer, let name = name {

                    // Extract pointer to `self` from void pointer:
                    let mySelf = Unmanaged<YourClass>.fromOpaque(observer).takeUnretainedValue()
                    // Call instance method:
                    mySelf.callback(name.rawValue as String)
                }
            },
            "myMessage" as CFString,
            nil,
            .deliverImmediately)
    }

    // ...
}

<小时>

另见 如何将 self 转换为 UnsafeMutablePointer输入 swift 以获取更多信息关于对象指针和 C 指针之间的桥接".


See also How to cast self to UnsafeMutablePointer<Void> type in swift for more information about the "bridging" between object pointers and C pointers.

这篇关于如何使用实例方法作为只接受 func 或文字闭包的函数的回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆