1.選擇使用閉包方式,進行數據綁定
2.經過監聽ViewModel的屬性觀察器,刷新接口數據,調用閉包
3.最後View/ViewController完成全部UI交互git
閉包的做用,控制交互過程
github
typealias Nothing = ()->()
var reloadTableViewClosure: Nothing?
var showAlertClosure: Nothing?複製代碼
利用屬性觀察器,觸發調用閉包的時機,使UI作出響應
api
var cellViewModels: [CellViewModel] = [CellViewModel]() {
didSet {
reloadTableViewClosure?()
}
}
var alertMessage: String? {
didSet {
showAlertClosure?()
}
}複製代碼
ViewController
bash
import UIKit
import SDWebImage
class ViewController: UIViewController {
@IBOutlet weak var tableview: UITableView!
lazy var viewmodel: ViewModel = {
return ViewModel()
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
createui()
createvm()
}
func createui() {
self.view.backgroundColor = .black
tableview.register(UINib(nibName: "ViewCell", bundle: nil), forCellReuseIdentifier: "viewcell")
}
func createvm() {
viewmodel.reloadTableViewClosure = { [weak self] in
DispatchQueue.main.async {
self?.tableview.reloadData()
}
}
viewmodel.showAlertClosure = { [weak self] in
DispatchQueue.main.async {
if let message = self?.viewmodel.alertMessage {
self?.showAlert( message )
}
}
}
viewmodel.initData()
}
func showAlert( _ message: String ) {
let alert = UIAlertController(title: "Alert", message: message, preferredStyle: .alert)
alert.addAction( UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
//MARK: TableViewDelegate
extension ViewController: UITableViewDelegate,UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewmodel.numberCells
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "viewcell", for: indexPath) as? ViewCell else {
fatalError("Cell not exists in storyboard")
}
cell.config = viewmodel.dataViewModel(indexPath)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
viewmodel.promptMessage(indexPath)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 160
}
}
複製代碼
ViewModel閉包
import UIKit
struct CellViewModel {
let titleText: String
let descText: String
let imageUrl: String
let dateText: String
}
typealias Nothing = (()->())
class ViewModel: NSObject {
//總體思路就是經過屬性觀察器和閉包實現數據的雙向綁定,在viewModel中處理邏輯
//使用閉包來控制交互過程
var reloadTableViewClosure: Nothing?
var showAlertClosure: Nothing?
//
var cellViewModels: [CellViewModel] = [CellViewModel]() {
didSet {
reloadTableViewClosure?()
}
}
var alertMessage: String? {
didSet {
showAlertClosure?()
}
}
//
var numberCells: Int {
return cellViewModels.count
}
func initData(api: APIService = APIService()) {
api.fetchPopularPhoto { [weak self] (success, photos, error) in
if let error = error {
self?.alertMessage = error.rawValue
} else {
self?.processFetchedPhoto(photos: photos)
}
}
}
func dataViewModel(_ index: IndexPath) -> CellViewModel {
return cellViewModels[index.row]
}
func promptMessage(_ index: IndexPath) {
if index.row%2 == 0 {
alertMessage = "點擊\(index.row)"
}
}
func processFetchedPhoto(photos: [Photo]) {
var num = [CellViewModel]()
for photo in photos {
num.append(createCellViewModel(photo: photo))
}
//刷新tableview
cellViewModels = num
}
//這樣的處理是爲了保證model不參與直接交互,而是採用viewmodel接管數據進行view層的交互
func createCellViewModel( photo: Photo ) -> CellViewModel {
//Wrap a description
var descTextContainer: [String] = [String]()
if let camera = photo.camera {
descTextContainer.append(camera)
}
if let description = photo.description {
descTextContainer.append( description )
}
let desc = descTextContainer.joined(separator: " - ")
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
return CellViewModel( titleText: photo.name,
descText: desc,
imageUrl: photo.image_url,
dateText: dateFormatter.string(from: photo.created_at) )
}
}複製代碼
GitHubDemo: github.com/marst123/ta…app