在 GitHub 有許多開源的專案是值得我們學習的, 尤其是當接觸新事物的時候, SwiftUI-Combine 是一個使用 SwiftUI 及 Combine 的資料顯示樣板, 是新接觸的人可以有的不錯練習!
本篇文章將注重與 repo 內 Combine的部分.
// SearchUserViewModel.swift
import UIKit.UIImage
import Combine
final class SearchUserViewModel: ObservableObject {
// 1
@Published var name = "ra1028"
@Published private(set) var users = [User]()
@Published private(set) var userImages = [User: UIImage]()
private var searchCancellable: Cancellable? {
didSet { oldValue?.cancel() }
}
// 2
func search() {...}
func fetchImage(for user: User) {...}
}
private(set)
的方式限制 Subjcet.value 可用範圍 func search() {
...
_ = URLSession.shared.dataTaskPublisher(for: request) // 1
.map { $0.data } // 2
.decode(type: SearchUserResponse.self, decoder: JSONDecoder())
.map { $0.items }
.replaceError(with: []) // 3
.receive(on: RunLoop.main)
.assign(to: \.users, on: self)
}
Data
, Decoder 要使用注入的方式使用如此一來, 就可以在 SwiftUI 內使用
import SwiftUI
struct SearchUserView: View {
@ObservedObject var viewModel = SearchUserViewModel()
var body: some View {
NavigationView {
VStack {
SearchUserBar(text: $viewModel.name) { // 1
self.viewModel.search()
}
List(viewModel.users) { user in // 2
SearchUserRow(viewModel: self.viewModel, user: user)
.onAppear { self.viewModel.fetchImage(for: user) }
}
}
.navigationBarTitle(Text("Users"))
}
}
}
在 UIKit 與 非 Combine 的情形下, 要實作出同樣的功能時需要使用 UITableView.reloadData() 的方式注入 URLSession.dataTask. 使用 Combine 之後, 仿佛 FlowChart(控制流程圖)在程式碼現型一般, 是很好理解的 code!