一、通知
1、发送通知
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、发送通知
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "headItemClick"), object: nil, userInfo: ["indexRow": String(indexPath.row)])
}
2、接受通知,并取出数据
ViewDidLoad中调用:
NotificationCenter.default.addObserver(self, selector: #selector(headItemClick(notif:)), name: NSNotification.Name(rawValue: "headItemClick"), object: nil)
extension ZJDiscoverViewController{
@objc func headItemClick(notif:NSNotification) {
//转成int类型
let index = (notif.userInfo!["indexRow"] as? String)!
let row = Int(index)
print("已经把主要点击的数据传递到VC中来了:",row!)
}
}
3、移除通知
deinit方法,相当于OC的delloc
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "headItemClick"), object: nil)
}
3、响应事件
@objc func tongzhiwo() {
print("饿哦们接收到了通知哦")
}
4、注销通知:在注册通知的页面加上
deinit {
NotificationCenter.default.removeObserver(self)
}
二、代理
1、在NextViewController中创建代理
@objc protocol nextVCDelegate{
func nextVCTextFieldValue(value: String?)
}
2、声明代理
weak var delegate : nextVCDelegate?
3、在HomeViewController中调用代理
viewDidLoad中调用方法:
let nextVC = NextViewController()
nextVC.delegate = self
extension HomeViewController : nextVCDelegate{
func nextVCTextFieldValue(value: String?) {
print("调用了代理",value as Any)
}
}
协议的继承:
a、secondNextVCDelegate继承协议nextVCDelegate,这样secondNextVCDelegate就拥有nextVCDelegate的协议nextVCTextFieldValue
b、Swift的协议要求都是必须实现的,所以如果我们想要协议变成可选的,那么就要使用调用OC的功能,在方法前添加@objc,同时也添加optional表示为可选。
@objc protocol nextVCDelegate{
func nextVCTextFieldValue(value: String?)
}
@objc protocol secondNextVCDelegate : nextVCDelegate {
@objc optional func breath(value: String)
}
三、KVO
1、为什么修改时属性要用@objc 和 dynamic呢?
首先我们了解一下swift是静态语言,并没有OC的动态分发机制。
- 而KVO的本质是基于runtime的动态分发机制,通过key来监听Value的值。
- OC能够实现监听因为都遵守了NSKeyValueCoding协议。
- OC所有的类都是继承自NSObject,其默认已经遵守了该协议,但Swift不是基于runtime的,
Swift 中的属性处于性能等方面的考虑默认是关闭动态分发的,只有在属性前加 dynamic才会开启运行时,允许监听属性的变化。
- 添加@objc是让属性拥有OC的属性。
a.普通的监听方式
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)
}
}
方法调用:
let dog = Dog()
dog.name = "zhang"
打印结果:
willSet zhang
Just changed from kai to zhang
b.RXSwift的监听方式
extension ViewController{
//1、设置监听的属性。
class Dog: NSObject {
@objc dynamic var name : String?
}
//2、这里是RXSwift的监控方式。
func userKVO() {
let dog = Dog()
dog.name = "zhang2112"
dog.rx.observe(String.self, "name").subscribe { name in
print("KVO监控的名字为:\(name)")
}.disposed(by: bag)
dog.name = "zhang"
dog.name = "wang"
}
}
我们观察可以发现,使用swift的方法设置KVO监控,需要重写observe方法,并在里面设置监听的属性,而使用RxSwift方法则直接设置监听即可,调用起来更加方便。
重要知识点:
RxCocoa 提供了 2 个可观察序列 rx.observe 和 rx.observeWeakly,它们都是对 KVO 机制的封装,二者的区别如下。
1、性能比较
- rx.observe 更加高效,因为它是一个 KVO 机制的简单封装。
- rx.observeWeakly 执行效率要低一些,因为它要处理对象的释放防止弱引用(对象的 dealloc 关系)。
2、应用场景比较
- 在可以使用 rx.observe 的地方都可以使用 rx.observeWeakly。
- 使用 rx.observe 时路径只能包括 strong 属性,否则就会有系统崩溃的风险。而 rx.observeWeakly 可以用在 weak 属性上。
class ViewController: UIViewController {
let disposeBag = DisposeBag()
@objc dynamic var message = "hangge.com"
override func viewDidLoad() {
super.viewDidLoad()
//定时器(1秒执行一次)
Observable.interval(1, scheduler: MainScheduler.instance)
.subscribe(onNext: { [unowned self] _ in
//每次给字符串尾部添加一个感叹号
self.message.append("!")
}).disposed(by: disposeBag)
//监听message变量的变化
_ = self.rx.observeWeakly(String.self, "message")
.subscribe(onNext: { (value) in
print(value ?? "")
})
}
}
四、闭包传值(OC的block)
场景:自定义的UIView,里面有多个按钮,我们需要监控各个按钮的点击,并且为点击的按钮传值,这时我们就需要OC中的block也就是:
1、定义一个闭包
typealias swiftBlock = (_ str: String) -> Void
2、声明闭包的类型
var callBack : swiftBlock?
3、实现闭包,由于要在其它类中调用,所以需要添加@escaping函数。
func callBackBlock(_ block: @escaping swiftBlock) {
callBack = block
}
4、使用
@IBAction func dianZan(_ sender: Any) {
if callBack != nil {
callBack!("点赞")
}
print("点赞")
}
5、在VC中调用
override func layoutSubviews() {
super.layoutSubviews()
loadUI()
footView.callBackBlock { (str) in
print("~~~~~~~传过来的参数:\(str)")
}
}