Ответ 1
Обратный вызов является указателем на функцию 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
внутри закрытия для обновления пользовательского интерфейса при получении уведомления.
Существует решение, но это немного сложно из-за
Быстрая строгая система.
Точно так же, как в Swift 2 - UnsafeMutablePointer <Void> объекту, вы можете преобразовать указатель в
self
указателю на пустоту, передать это как параметр 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)
}
// ...
}
См. также Как использовать self для UnsafeMutablePointer <Void> введите быстрый для получения дополнительной информации о "мостике" между указателями объектов и указателями C.