swift的通知、代理、KVO&RXSwift鍵值觀察、閉包(block)

一、通知

1、發(fā)送通知

NotificationCenter.default.post(name: NSNotification.Name(rawValue: "zhangkaikai"), object: nil, userInfo: nil)

2、接收通知

NotificationCenter.default.addObserver(self, selector: #selector(tongzhiwo), name: NSNotification.Name(rawValue: "zhangkaikai"), object: nil)

思考:如果我們需要通知傳值呢?
1、發(fā)送通知

 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
     NotificationCenter.default.post(name: NSNotification.Name(rawValue: "headItemClick"), object: nil, userInfo: ["indexRow": String(indexPath.row)])
}

2、接受通知,并取出數(shù)據(jù)

ViewDidLoad中調(diào)用:
NotificationCenter.default.addObserver(self, selector: #selector(headItemClick(notif:)), name: NSNotification.Name(rawValue: "headItemClick"), object: nil)

extension ZJDiscoverViewController{
   @objc func headItemClick(notif:NSNotification) {
    //轉(zhuǎn)成int類型
    let index = (notif.userInfo!["indexRow"] as? String)!
    let row = Int(index)
    print("已經(jīng)把主要點(diǎn)擊的數(shù)據(jù)傳遞到VC中來(lái)了:",row!)
    }
}

3、移除通知
deinit方法,相當(dāng)于OC的delloc

deinit {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "headItemClick"), object: nil)
       }

3、響應(yīng)事件

 @objc func tongzhiwo()  {
       print("餓哦們接收到了通知哦")
 }

4、注銷通知:在注冊(cè)通知的頁(yè)面加上

deinit {
    NotificationCenter.default.removeObserver(self)
}

二、代理

1、在NextViewController中創(chuàng)建代理

@objc protocol nextVCDelegate{
      func nextVCTextFieldValue(value: String?)
}

2、聲明代理

 weak var delegate : nextVCDelegate?

3、在HomeViewController中調(diào)用代理

  viewDidLoad中調(diào)用方法:
  let nextVC = NextViewController()
  nextVC.delegate = self

extension HomeViewController : nextVCDelegate{
    func nextVCTextFieldValue(value: String?) {
        print("調(diào)用了代理",value as Any)
    }
}

協(xié)議的繼承:
a、secondNextVCDelegate繼承協(xié)議nextVCDelegate,這樣secondNextVCDelegate就擁有nextVCDelegate的協(xié)議nextVCTextFieldValue
b、Swift的協(xié)議要求都是必須實(shí)現(xiàn)的,所以如果我們想要協(xié)議變成可選的,那么就要使用調(diào)用OC的功能,在方法前添加@objc,同時(shí)也添加optional表示為可選。

@objc protocol nextVCDelegate{
    func nextVCTextFieldValue(value: String?)
}

@objc protocol secondNextVCDelegate : nextVCDelegate {
    @objc optional func breath(value: String)
}

三、KVO

1、為什么修改時(shí)屬性要用@objc 和 dynamic呢?

首先我們了解一下swift是靜態(tài)語(yǔ)言,并沒(méi)有OC的動(dòng)態(tài)分發(fā)機(jī)制。

  • 而KVO的本質(zhì)是基于runtime的動(dòng)態(tài)分發(fā)機(jī)制,通過(guò)key來(lái)監(jiān)聽(tīng)Value的值。
  • OC能夠?qū)崿F(xiàn)監(jiān)聽(tīng)因?yàn)槎甲袷亓薔SKeyValueCoding協(xié)議。
  • OC所有的類都是繼承自NSObject,其默認(rèn)已經(jīng)遵守了該協(xié)議,但Swift不是基于runtime的, Swift 中的屬性處于性能等方面的考慮默認(rèn)是關(guān)閉動(dòng)態(tài)分發(fā)的,只有在屬性前加 dynamic才會(huì)開啟運(yùn)行時(shí),允許監(jiān)聽(tīng)屬性的變化。
  • 添加@objc是讓屬性擁有OC的屬性。
a.普通的監(jiān)聽(tīng)方式
  class Dog: NSObject {
        @objc dynamic var name = "kai"{
            willSet(newName){
                print("willSet",newName)
            }
            didSet(oldName){
                print("Just changed from \(oldName) to \(self.name)")
            }
         }
    }
//重寫chongobserve方法
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "name" {
            print("~~~~age被改變了", dog.name)
            print(change as Any)
           }
    }

方法調(diào)用:

let dog = Dog()
dog.name = "zhang"

打印結(jié)果:

willSet zhang
Just changed from kai to zhang
b.RXSwift的監(jiān)聽(tīng)方式
extension ViewController{
    //1、設(shè)置監(jiān)聽(tīng)的屬性。
    class Dog: NSObject {
        @objc dynamic var name : String?
    }
    
    //2、這里是RXSwift的監(jiān)控方式。
    func userKVO() {
        let dog = Dog()
        dog.name = "zhang2112"
        dog.rx.observe(String.self, "name").subscribe { name  in
            print("KVO監(jiān)控的名字為:\(name)")
        }.disposed(by: bag)
        
        dog.name = "zhang"
        dog.name = "wang"
    }
}

我們觀察可以發(fā)現(xiàn),使用swift的方法設(shè)置KVO監(jiān)控,需要重寫observe方法,并在里面設(shè)置監(jiān)聽(tīng)的屬性,而使用RxSwift方法則直接設(shè)置監(jiān)聽(tīng)即可,調(diào)用起來(lái)更加方便。


重要知識(shí)點(diǎn):

RxCocoa 提供了 2 個(gè)可觀察序列 rx.observe 和 rx.observeWeakly,它們都是對(duì) KVO 機(jī)制的封裝,二者的區(qū)別如下。

1、性能比較
  • rx.observe 更加高效,因?yàn)樗且粋€(gè) KVO 機(jī)制的簡(jiǎn)單封裝。
  • rx.observeWeakly 執(zhí)行效率要低一些,因?yàn)樗幚韺?duì)象的釋放防止弱引用(對(duì)象的 dealloc 關(guān)系)。
2、應(yīng)用場(chǎng)景比較
  • 在可以使用 rx.observe 的地方都可以使用 rx.observeWeakly。
  • 使用 rx.observe 時(shí)路徑只能包括 strong 屬性,否則就會(huì)有系統(tǒng)崩潰的風(fēng)險(xiǎn)。而 rx.observeWeakly 可以用在 weak 屬性上。
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    @objc dynamic var message = "hangge.com"
     
    override func viewDidLoad() {
        super.viewDidLoad()
       
        //定時(shí)器(1秒執(zhí)行一次)
        Observable<Int>.interval(1, scheduler: MainScheduler.instance)
            .subscribe(onNext: { [unowned self] _ in
                //每次給字符串尾部添加一個(gè)感嘆號(hào)
                self.message.append("!")
            }).disposed(by: disposeBag)
         
        //監(jiān)聽(tīng)message變量的變化
        _ = self.rx.observeWeakly(String.self, "message")
            .subscribe(onNext: { (value) in
            print(value ?? "")
        })
    }
}

四、閉包傳值(OC的block)

場(chǎng)景:自定義的UIView,里面有多個(gè)按鈕,我們需要監(jiān)控各個(gè)按鈕的點(diǎn)擊,并且為點(diǎn)擊的按鈕傳值,這時(shí)我們就需要OC中的block也就是:

1、定義一個(gè)閉包

typealias shopBtnClickBlock = (_ tag:Int) ->Void

2、聲明閉包的類型

    var btnClickblock : shopBtnClickBlock?

3、實(shí)現(xiàn)閉包,由于要在其它類中調(diào)用,所以需要添加@escaping函數(shù)。

    //Mark: - 購(gòu)買等按鈕點(diǎn)擊事件
    @objc func gridBtnClick(button:UIButton){
        btnClickblock?(button.tag)
    }
    

4、使用

 @IBAction func dianZan(_ sender: Any) {
        if callBack != nil {
            callBack!("點(diǎn)贊")
        }
        print("點(diǎn)贊")
 }

5、在VC中調(diào)用

   view.btnClickblock = {str in
            print("打印出來(lái)block內(nèi)容為:\(str)")
        }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容