在“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)
导致此编译器错误:
“C函数指针只能通过对'func'或文字闭包的引用形成”
答案 0 :(得分:32)
回调是指向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 2 - UnsafeMutablePointer<Void> to object类似,您可以将指针转换为
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)
}
// ...
}
关闭充当了蹦床&#34;实例方法。
指针是未保留的引用,因此您必须确保 在取消分配对象之前删除观察者。
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)
}
// ...
}
有关详细信息,另请参阅How to cast self to UnsafeMutablePointer<Void> type in swift 关于&#34;桥接&#34;在对象指针和C指针之间。
答案 1 :(得分:1)
在我的情况下,我想从闭合中调用的函数在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)
}