Swift - 正確使用CFNotificationCenterAddObserver w /回調


Swift - 正確使用CFNotificationCenterAddObserver w /回調

問題描述

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'或一個文字閉包而形成



想法?

只有一個全局函數或一個閉包(不捕獲任何狀態),$ b

 


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

    // ...
}

 

 

 

 

Update for Swift 5:

發送通知

sendNotificationForMessageWithIdentifier(identifier: "broadcastStarted")

func sendNotificationForMessageWithIdentifier(identifier : String) {

        let center : CFNotificationCenter = CFNotificationCenterGetDarwinNotifyCenter()

//        let userInfo : CFDictionary = CFDictionary(info)

        let identifierRef : CFNotificationName = CFNotificationName(identifier as CFString)

        CFNotificationCenterPostNotification(center, identifierRef, nil, nil, true)

    }

 

///通知回調

    func callback(_ name : String) {

        print("received notification: \(name)")

        mainView.vedioV.uploadBtn.isHidden = false

        ///視頻預覽

        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in

            let userDefault = UserDefaults.init(suiteName: "group.dc.record")

            let pathstr = userDefault?.object(forKey: "videoFilePath")

            guard let path = pathstr else {

                return

            }

            self?.vm.urlVedioString = URL(fileURLWithPath: path as! String)

            self?.mainView.vedioV.loadImageReview(url: URL(fileURLWithPath: path as! String))

        }

    }

    

    ///通知注冊

    func registerObserver() {

        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<OTCAppealVC>.fromOpaque(observer).takeUnretainedValue()

                // Call instance method:

                mySelf.callback(name.rawValue as String)

            }

        },

                                        "broadcastFinished" as CFString,

                                        nil,

                                        .deliverImmediately)

    }

 

通知移除

deinit {

        let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())

        let cfName: CFNotificationName = CFNotificationName("broadcastFinished" as CFString)

        CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer, cfName, nil)

    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM