MVC不够看了。项目越做到后面VC里的代码行数蹭蹭蹭的往上涨啊!
9d82d158ccbf6c81b0aa6bcbb43eb13533fa4077.jpg
概念之类的自己百度,本文只讲如何实现仅有一个Tableview的项目。
总共三个文件
7.png
ViewController 尽量保持简单,只保留控件,IBAction IBoutlet Autolayout之类的就够了。
class ViewController: UIViewController,TableviewModelDelegate {
@IBOutlet weak var tableview:UITableView
//数据源VM,负责数据请求和持有。
var lessonVM:LessonViewModel!
//TableViewVM,负责监听数据源对象,实现tableviewdelegate
var tableVM:TableViewModel!
override func viewDidLoad() {
super.viewDidLoad()
self.lessonVM = LessonViewModel.init()
//此对象持有lessonVM.
self.tableVM = TableViewModel.init(identifier: "cellIdentify", viewModel: self.lessonVM)
}
//TableviewVMDelegate,数据监听被触发后,调用此处进行界面刷新。
func reloadTableview() -> Void {
self.tableview.reloadData()
}
}
emmmmm,ViewController就这么多。就算在控件的操作过程中有逻辑判断的部分也尽量在viewmodel中封装好让外面调用。TablviewDelegate之类的东西会放在其他地方避免版本迭代无限制的扩张。TableviewModelDelegate和reloadTableview()方法下面会说到。
接下来是数据源部分
class LessonViewModel: NSObject {
//数据源对象
dynamic var lessonArray:NSMutableArray = [];
//获取数据
public func getLessonFromFile () {
let dataArray:NSMutableArray = FileUtility.readDateFromFile()
let tempDataArray:NSMutableArray = FileUtility.getEntityArray(fromDatas: dataArray)
self.lessonArray = NSMutableArray(array: tempDataArray)
}
}
我这里的数据源是来自本地的File解析,正常情况下的网络请求来的数据也没多大差,网络底层封装好,上层调用完之后记得把响应对象赋值给类对象lessonArray。
(dynamic关键字一定不能忘)
下面是最重要的
let DEFINEKEYPATH = "lessonArray"
protocol TableviewModelDelegate:NSObjectProtocol {
func reloadTableview() -> Void
}
class TableViewModel: NSObject,UITableViewDelegate,UITableViewDataSource {
var tableviewID:String = ""
var lessonVM:LessonViewModel!
private var myContext = 0
weak var delegate:TableviewModelDelegate?
init(identifier:NSString,viewModel:LessonViewModel) {
super.init()
self.lessonVM = viewModel
self.tableviewID = identifier as String
//属性监听
bindViewModel()
//数据获取
self.lessonVM.getLessonFromFile()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//监听移除
deinit {
lessonVM.removeObserver(self, forKeyPath: DEFINEKEYPATH)
}
//监听数据源的目标属性名,属性变化后在底部的observeValue方法会响应
func bindViewModel() -> Void {
lessonVM.addObserver(self, forKeyPath: DEFINEKEYPATH, options: [.new, .old], context: &myContext)
}
//-------------------------------TableViewDelegate--------------------------
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.lessonVM.lessonArray.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let voc:Vocabulary = self.lessonVM.lessonArray.object(at: indexPath.row) as! Vocabulary
let cell:LessonCell = tableView.customdq(tableviewID) as! LessonCell
cell.lblGerman.text = "German: "+voc.german
cell.lblEnglish.text = "English: "+voc.english
return cell
}
}
//-------------------------------------------------------------------------------------
extension TableViewModel {
//KVO
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == DEFINEKEYPATH {
//调用VC刷新页面
DispatchQueue.main.async { [weak self] in
self?.delegate?.reloadTableview()
}
}
}
}
本类负责tableviewDelegate实现,监听数据源目标属性,实现监听刷新页面tableview。
大概就是这么个意思,每一部分都做到了完全的解藕。搞定了数据源和逻辑层,做到数据源的变动可以自动刷新,所以也有一点响应式编程的意思。
有看不懂的可以邮件联系我。后期收集到更多想法会及时更新文章的辞藻。
建了Swift的QQ交流群 859978655,欢迎大家加入。
网友评论