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 也可以发挥重要作用。如下图的案例,当开关打开(关闭)的时候,按钮可以(不能)点击,点击发送通知按钮,蓝色的标签显示发送的通知内容。
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")
}
}