使用 Combine 接收和处理事件
自定义和接收来自异步源的事件。
接下来将使用一个简单的实例来讲述如何使用Combine
接收和处理事件。
假设您的应用中需要根据一个文本值实时更新列表内容,例如根据关键字进行搜索,那么在文字实时变化的过程中,AppKit会同时发送通知Notification
以供订阅。
使用订阅者订阅
步骤一:使用NotificationCenter
提供的方法publisher(for:object:)
生成一个发布者
let pub = NotificationCenter.default
.publisher(for: NSControl.textDidChangeNotification, object: filterField)
步骤二:系统提供了2个内置订阅者,可供使用
sink(receiveCompletion:receiveValue:)
中的2个闭包回调,第一个闭包接收Subscribers.Completion
枚举类型标识当前是状态是成功还是失败,第二闭包接收结果值。assign(to:on:)
立即将它接收到的每个元素分配给给定对象的属性,使用键路径(key path)来指示属性。
let sub = NotificationCenter.default
.publisher(for: NSControl.textDidChangeNotification, object: filterField)
.sink(receiveCompletion: { print ($0) },
receiveValue: { print ($0) })
使用运算符更改输出类型
步骤三:使用map(_:)
运算符转换为不同类型,首先将Notification
的object
属性转换为NSTextField
,再取得其字符值
let sub = NotificationCenter.default
.publisher(for: NSControl.textDidChangeNotification, object: filterField)
.map( { ($0.object as! NSTextField).stringValue } )
.sink(receiveCompletion: { print ($0) },
receiveValue: { print ($0) })
同样的,您也可以使用assign(to:on:)
,如下将最后的值赋予了myViewModel
的属性filterString
let sub = NotificationCenter.default
.publisher(for: NSControl.textDidChangeNotification, object: filterField)
.map( { ($0.object as! NSTextField).stringValue } )
.assign(to: \MyViewModel.filterString, on: myViewModel)
使用运算符自定义发布者
使用运算符来改进此事件处理链的三种方法
使用
filter(_:)
运算符忽略特定长度以下的输入或拒绝非字母数字字符使用
debounce(for:scheduler:options:)
运算符指定事件发送最短时间间隔使用
receive(on:options:)
用于将回调传递给主线程更新UI
步骤四:使用运算符完善发布流程
let sub = NotificationCenter.default
.publisher(for: NSControl.textDidChangeNotification, object: filterField)
.map( { ($0.object as! NSTextField).stringValue } )
.filter( { $0.unicodeScalars.allSatisfy({CharacterSet.alphanumerics.contains($0)}) } )
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.receive(on: RunLoop.main)
.assign(to:\MyViewModel.filterString, on: myViewModel)
取消发布
sink(receiveCompletion:receiveValue:)
与assign(to:on:)
实现了Cancellable
协议,如果您需要取消发布,只需要调用:
sub?.cancel()