Swift - 正确使用CFNotificationCenterAddObserver w /回调 [英] Swift - Proper use of CFNotificationCenterAddObserver w/callback
问题描述
in'ViewController.swift'
创建此回调:
func callback(cf:CFNotificationCenter !,
ump:UnsafeMutablePointer< Void>,
cfs:CFString !,
up:UnsafePointer< Void> ;,
cfd:CFDictionary! - >无效{
}
使用此观察者:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
nil,
self.callback,
myMESSage,
CFNotificationSuspensionBehavior.DeliverImmediately)
导致此编译器错误:
AC函数指针只能通过引用一个'func'或一个文字闭包而形成
想法?
c中的CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
nil,
{(_,observer,name,_,_)print(received notification:\(name) $ b},
myMessage,
nil,
.DeliverImmediately)
$ b b
但是因为闭包不能捕获上下文,所以没有直接引用 self
及其属性和实例方法。
例如,您不能添加
self.label.stringValue =got it
//错误:不能从捕获上下文的闭包形成C函数指针
当一个通知到达时,UI。
有一个解决方案,但由于
Swift的严格类型系统,它有点复杂。
类似于 Swift 2 - UnsafeMutablePointer< Void>到对象,你可以将指针转换为
self
为void指针,传递 observer
参数
到注册,并将其转换回
中的对象指针回调。
class YourClass {
func callback(name:String){
print(received notification:\(name))
}
func registerObserver(){
//指向`self`的void指针:
let observer = UnsafePointer< Void>(Unmanaged.passUnretained(self).toOpaque())
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
observer,
{(_,observer,name,_,_) - > Void in
//提取指针从void指针到`self`:
let mySelf = Unmanaged< YourClass> .fromOpaque(
COpaquePointer(observer))。takeUnretainedValue()
//调用实例方法:
mySelf .callback(name as String)
},
myMessage,
nil,
.DeliverImmediately)
}
// ..
}
闭包作为实例方法的trampoline / p>
指针是一个未保存的引用,因此必须确保
在释放对象之前被移除。
更新Swift 3:
class YourClass {
func callback(_ name:String){
print(received notification:\(name))
}
func registerObserver(){
//指向`self`的指针:
let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
observer,
{(_,observer,name,_,_) - >
如果let observer = observer,则let name = name {
// void void指针指向`self`指针:
let mySelf =非托管< YourClass> .fromOpaque (观察者).takeUnretainedValue()
//调用实例方法:
mySelf.callback(name.rawValue as String)
}
},
myMessageas CFString,
nil,
.deliverImmediately)
}
// ...
}
in 'ViewController.swift'
Creating this callback:
func callback(cf:CFNotificationCenter!,
ump:UnsafeMutablePointer<Void>,
cfs:CFString!,
up:UnsafePointer<Void>,
cfd:CFDictionary!) -> Void {
}
Using this observer:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
nil,
self.callback,
"myMESSage",
nil,
CFNotificationSuspensionBehavior.DeliverImmediately)
Results in this compiler error: "A C function pointer can only be formed from a reference to a 'func' or a literal closure"
Thoughts?
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.
So this does work:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
nil,
{ (_, observer, name, _, _) in
print("received notification: \(name)")
},
"myMessage",
nil,
.DeliverImmediately)
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
inside the closure to update the UI when a notification arrived.
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.
Update for 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)
}
// ...
}
这篇关于Swift - 正确使用CFNotificationCenterAddObserver w /回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!