Swift Combine 通过用户输入更新声明式 UI 从入门到精通十五
import UIKit
import Combine
class ViewController: UIViewController {
@IBOutlet weak var github_id_entry: UITextField! // 1
var usernameSubscriber: AnyCancellable?
// username from the github_id_entry field, updated via IBAction
// @Published is creating a publisher $username of type <String, Never>
@Published var username: String = "" // 2
// github user retrieved from the API publisher. As it's updated, it
// is "wired" to update UI elements
@Published private var githubUserData: [GithubAPIUser] = []
// MARK - Actions
@IBAction func githubIdChanged(_ sender: UITextField) {
username = sender.text ?? "" // 3
print("Set username to ", username)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
usernameSubscriber = $username // 4
.throttle(for: 0.5, scheduler: myBackgroundQueue, latest: true) // 5
// ^^ scheduler myBackGroundQueue publishes resulting elements
// into that queue, resulting on this processing moving off the
// main runloop.
.removeDuplicates() // 6
.print("username pipeline: ") // debugging output for pipeline
.map { username -> AnyPublisher<[GithubAPIUser], Never> in // 7
return GithubAPI.retrieveGithubUser(username: username)
}
// ^^ type returned by retrieveGithubUser is a Publisher, so we use
// switchToLatest to resolve the publisher to its value
// to return down the chain, rather than returning a
// publisher down the pipeline.
.switchToLatest() // 8
// using a sink to get the results from the API search lets us
// get not only the user, but also any errors attempting to get it.
.receive(on: RunLoop.main)
.assign(to: \.githubUserData, on: self) // 9