为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用实例方法作为只接受func或文字闭包的函数的回调

如何使用实例方法作为只接受func或文字闭包的函数的回调

守着一只汪 2019-08-05 14:22:28
如何使用实例方法作为只接受func或文字闭包的函数的回调在“ViewController.swift”中我创建了这个回调:func callback(cf:CFNotificationCenter!,      ump:UnsafeMutablePointer<Void>,      cfs:CFString!,      up:UnsafePointer<Void>,      cfd:CFDictionary!) -> Void {}使用此观察者:CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),      nil,      self.callback,      "myMESSage",      nil,      CFNotificationSuspensionBehavior.DeliverImmediately)导致此编译器错误:“AC函数指针只能通过对'func'或文字闭包的引用形成”
查看完整描述

2 回答

?
犯罪嫌疑人X

TA贡献2080条经验 获得超4个赞

回调是指向C函数的指针,在Swift中,您只能传递全局函数或闭包(不捕获任何状态),但不能传递实例方法。

所以这确实有效:

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

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

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

在闭包内部,在通知到达时更新UI。

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

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)
    }
    // ...}

闭包充当实例方法的“蹦床”。

指针是未保留的引用,因此必须确保在取消分配对象之前删除观察者。


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)
    }
    // ...}

有关对象指针和C指针之间“桥接”的更多信息,另请参见如何将self转换为UnsafeMutablePointer <Void>键入swift


查看完整回答
反对 回复 2019-08-05
?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

在我的例子中,我想从我的闭包中调用的函数是在AppDelegate中。所以我能够使用委托从闭包中调用函数而不使用self。这是否是一个主意是具有更多经验的人必须评论的东西。

        self.pingSocket = CFSocketCreate(kCFAllocatorDefault, AF_INET, SOCK_DGRAM, IPPROTO_ICMP,CFSocketCallBackType.dataCallBack.rawValue, {socket, type, address, data, info in
            //type is CFSocketCallBackType
            guard let socket = socket, let address = address, let data = data, let info = info else { return }// stuff deleted, including use of C pointers
            let appDelegate = NSApplication.shared.delegate as! AppDelegate
            appDelegate.receivedPing(ip: sourceIP, sequence: sequence, id: id)
            //}
            return
        }, &context)extension AppDelegate: ReceivedPingDelegate {
    func receivedPing(ip: UInt32, sequence: UInt16, id: UInt16) {
        // stuff deleted
    }}protocol ReceivedPingDelegate: class {
    func receivedPing(ip: UInt32, sequence: UInt16, id: UInt16)}


查看完整回答
反对 回复 2019-08-05
  • 2 回答
  • 0 关注
  • 439 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信