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


如何使用实例方法作为只接受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'或文字闭包的引用形成”


守着一只汪
浏览 442回答 2
2回答

犯罪嫌疑人X

回调是指向C函数的指针,在Swift中,您只能传递全局函数或闭包(不捕获任何状态),但不能传递实例方法。所以这确实有效:CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;(_,&nbsp;observer,&nbsp;name,&nbsp;_,&nbsp;_)&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("received&nbsp;notification:&nbsp;\(name)") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"myMessage", &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.DeliverImmediately)但由于闭包无法捕获上下文,因此您无法直接引用self其属性和实例方法。例如,您无法添加self.label.stringValue&nbsp;=&nbsp;"got&nbsp;it"//&nbsp;error:&nbsp;a&nbsp;C&nbsp;function&nbsp;pointer&nbsp;cannot&nbsp;be&nbsp;formed&nbsp;from&nbsp;a&nbsp;closure&nbsp;that&nbsp;captures&nbsp;context在闭包内部,在通知到达时更新UI。有一个解决方案,但由于Swift严格的类型系统,它有点复杂。与Swift 2 - UnsafeMutablePointer <Void>中的对象类似,您可以将指针转换&nbsp;self为void指针,将其作为observer参数传递给注册,并将其转换回回调中的对象指针。class&nbsp;YourClass&nbsp;{&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;callback(name&nbsp;:&nbsp;String)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("received&nbsp;notification:&nbsp;\(name)") &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;registerObserver()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Void&nbsp;pointer&nbsp;to&nbsp;`self`: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;observer&nbsp;=&nbsp;UnsafePointer<Void>(Unmanaged.passUnretained(self).toOpaque()) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observer, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;(_,&nbsp;observer,&nbsp;name,&nbsp;_,&nbsp;_)&nbsp;->&nbsp;Void&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Extract&nbsp;pointer&nbsp;to&nbsp;`self`&nbsp;from&nbsp;void&nbsp;pointer: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;mySelf&nbsp;=&nbsp;Unmanaged<YourClass>.fromOpaque( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;COpaquePointer(observer)).takeUnretainedValue() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Call&nbsp;instance&nbsp;method: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mySelf.callback(name&nbsp;as&nbsp;String) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"myMessage", &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.DeliverImmediately) &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;...}闭包充当实例方法的“蹦床”。指针是未保留的引用,因此必须确保在取消分配对象之前删除观察者。Swift 3更新:class&nbsp;YourClass&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;callback(_&nbsp;name&nbsp;:&nbsp;String)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("received&nbsp;notification:&nbsp;\(name)") &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;registerObserver()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Void&nbsp;pointer&nbsp;to&nbsp;`self`: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;observer&nbsp;=&nbsp;UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observer, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;(_,&nbsp;observer,&nbsp;name,&nbsp;_,&nbsp;_)&nbsp;->&nbsp;Void&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;let&nbsp;observer&nbsp;=&nbsp;observer,&nbsp;let&nbsp;name&nbsp;=&nbsp;name&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Extract&nbsp;pointer&nbsp;to&nbsp;`self`&nbsp;from&nbsp;void&nbsp;pointer: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;mySelf&nbsp;=&nbsp;Unmanaged<YourClass>.fromOpaque(observer).takeUnretainedValue() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Call&nbsp;instance&nbsp;method: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mySelf.callback(name.rawValue&nbsp;as&nbsp;String) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"myMessage"&nbsp;as&nbsp;CFString, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.deliverImmediately) &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;...}有关对象指针和C指针之间“桥接”的更多信息,另请参见如何将self转换为UnsafeMutablePointer <Void>键入swift。

慕田峪4524236

在我的例子中,我想从我的闭包中调用的函数是在AppDelegate中。所以我能够使用委托从闭包中调用函数而不使用self。这是否是一个好主意是具有更多经验的人必须评论的东西。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.pingSocket&nbsp;=&nbsp;CFSocketCreate(kCFAllocatorDefault,&nbsp;AF_INET,&nbsp;SOCK_DGRAM,&nbsp;IPPROTO_ICMP,CFSocketCallBackType.dataCallBack.rawValue,&nbsp;{socket,&nbsp;type,&nbsp;address,&nbsp;data,&nbsp;info&nbsp;in &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//type&nbsp;is&nbsp;CFSocketCallBackType &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;guard&nbsp;let&nbsp;socket&nbsp;=&nbsp;socket,&nbsp;let&nbsp;address&nbsp;=&nbsp;address,&nbsp;let&nbsp;data&nbsp;=&nbsp;data,&nbsp;let&nbsp;info&nbsp;=&nbsp;info&nbsp;else&nbsp;{&nbsp;return&nbsp;}//&nbsp;stuff&nbsp;deleted,&nbsp;including&nbsp;use&nbsp;of&nbsp;C&nbsp;pointers &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;appDelegate&nbsp;=&nbsp;NSApplication.shared.delegate&nbsp;as!&nbsp;AppDelegate &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appDelegate.receivedPing(ip:&nbsp;sourceIP,&nbsp;sequence:&nbsp;sequence,&nbsp;id:&nbsp;id) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&context)extension&nbsp;AppDelegate:&nbsp;ReceivedPingDelegate&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;receivedPing(ip:&nbsp;UInt32,&nbsp;sequence:&nbsp;UInt16,&nbsp;id:&nbsp;UInt16)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;stuff&nbsp;deleted &nbsp;&nbsp;&nbsp;&nbsp;}}protocol&nbsp;ReceivedPingDelegate:&nbsp;class&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;func&nbsp;receivedPing(ip:&nbsp;UInt32,&nbsp;sequence:&nbsp;UInt16,&nbsp;id:&nbsp;UInt16)}
打开App,查看更多内容
随时随地看视频慕课网APP