Combine 既可以在 SwiftUI 中使用,也可以在 UIKit 中使用。下面分别实践一下。
SwiftUI
声明式UI 响应式编程是未来移动开发的趋势,所以 Combine 对于 SwiftUI 来说是不可或缺的一部分,这也是为什么 Combine 会随着 SwiftUI 一起发布。在 SwiftUI 中任何一个 View 都可以作为 Subscriber。 SwiftUI 中的 View 协议定义了一个onReceive()
的函数可以将 View 变成 Subscriber。onReceive()
函数接收一个 Publisher,然后跟上一个类似于sink
的闭包,可以在其中操作@State
或@Binding
修饰的属性数据。
import SwiftUI
struct ContentView: View {
@State private var currentValue = "?"
var body: some View {
Text(currentValue)
.onReceive(Just("SwiftUI Combine")) { value in
self.currentValue = value
}
}
}
UIKit
虽然 SwiftUI Combine 是一对黄金搭档,但是在 UIKit 中 Combine 也可以发挥重要作用。如下图的案例,当开关打开(关闭)的时候,按钮可以(不能)点击,点击发送通知按钮,蓝色的标签显示发送的通知内容。
实现效果
代码语言:javascript复制import UIKit
import Combine
extension Notification.Name{
static var newMessage = Notification.Name("YungFan")
}
class ViewController: UIViewController {
@IBOutlet weak var allowMessageSwitch: UIButton!
@IBOutlet weak var sendButton: UIButton!
@IBOutlet weak var messageLabel: UILabel!
@Published var canSendMessage: Bool = false
private var cancellables: Set<AnyCancellable> = []
override func viewDidLoad() {
super.viewDidLoad()
// canSendMessage的改变绑定到Button的isEnabled上
$canSendMessage
.receive(on: DispatchQueue.main)
.assign(to: .isEnabled, on: sendButton)
.store(in: &cancellables)
// 通知需要绑定到messageLabel的text
NotificationCenter.default.publisher(for: .newMessage)
.map{ notification -> String in
notification.object as? String ?? ""
}
.assign(to: .text, on: messageLabel)
.store(in: &cancellables)
/*
// 上面的写法等于下面3句
let messagePublisher = NotificationCenter.Publisher(center: .default, name: .newMessage)
let messageSubscriber = Subscribers.Assign(object: messageLabel, keyPath: .text)
messagePublisher
.map{ notification -> String in
notification.object as? String ?? ""
}.subscribe(messageSubscriber)
*/
}
@IBAction func switchChanged(_ sender: UISwitch) {
// canSendMessage的改变随开关改变
self.canSendMessage = sender.isOn
}
@IBAction func buttonClicked(_ sender: UIButton) {
// 发送通知
NotificationCenter.default.post(name: .newMessage, object: "This is the (Int.random(in: 0...100)) message")
}
}