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