美文网首页iOS DeveloperIOSiOS 开发
在MVVM模式下基于协议开发Swift程序

在MVVM模式下基于协议开发Swift程序

作者: 陈阿票 | 来源:发表于2016-03-29 14:44 被阅读1519次

学习swift差不多两三个月了,其中看swift的官方文档看了差不多一个月,接下来的时间就在写swift的Demo,虽然开发起来顺风顺水,可是总感觉在走OC中的老路,在MVC下基于类开发程序。没有领悟到swift基于协议开发的精髓。昨天看到了Natasha的文章面向协议的 MVVM 架构介绍,觉得豁朗开朗,赶紧在自己的Demo中试了一下。废话不多说,开始正题。

图1

这是一个很简单的页面,包含4个label,3个button和一个uiview的分割线,运行起来的效果如下:

图2

在MVC下,正常的Cell里的代码一般是在awakeFromNib里设置label和button文字的颜色和字号,并且在传递完model的值之后设置label和button的数据。(下面的rgbColorWithHexString是UIColor的一个分类方法,显示16进制的颜色,AutoChangeSize是根据不同的屏幕放大乘以不同的倍数。这样写出来的程序在不同的设备上都运行良好)

override func awakeFromNib() {

super.awakeFromNib()

docImageView.layer.cornerRadius = docImageView.width / 2.0

docImageView.layer.masksToBounds = true

docName.textColor = UIColor.rgbColorWithHexString("#333333")

docName.font = UIFont.systemFontOfSize(CGFloat.AutoChangeSize(16))

levelLabel.textColor = UIColor.rgbColorWithHexString("#333333")

levelLabel.font = UIFont.systemFontOfSize(CGFloat.AutoChangeSize(13))

articleTitle.textColor = UIColor.rgbColorWithHexString("#333333")

articleTitle.font = UIFont.systemFontOfSize(CGFloat.AutoChangeSize(13))

articleDetail.textColor = UIColor.rgbColorWithHexString("#666666")

articleDetail.font = UIFont.systemFontOfSize(CGFloat.AutoChangeSize(12))

}

但是如果把文字大小和颜色都放在cell的类中,那如果需要一个和这个一样的cell,只是字号和字体颜色做下改变,并且增加一些点击事件。那么我们就不能很好的复用代码,当然可以考虑继承,也可以解决这个问题。但是既然是写swift,我们就把基于协议的特性发挥出来。

首先我们根据最终需要展示的样式,自定义一个xib,拖好控件,(最终如图1所示)这里的cell是动态高度的,只有content的高度是需要动态改变,所以我们需要把content多设置一个距离父控件右边15的约束,并且把numberOfline设置为0.最重要的一点是把Content Hugging Priority的Vertical的值设置为249. 关于具体的动态cell高度的设置请看我的这篇文章这里

然后创建一个DrugAdviceTableViewCell类,继承自UITableViewCell。并且拖好控件

@IBOutlet weak var time: UILabel!

@IBOutlet weak var title: UILabel!

@IBOutlet weak var content: UILabel!

@IBOutlet weak var buyNumber: UILabel!

@IBOutlet weak var buyButton: UIButton!

@IBOutlet weak var shopLocation: UIButton!

@IBOutlet weak var phoneNumber: UIButton!

然后我们需要的是在这个类里定义两个协议

protocol DrugAdviceTableViewCellDataSource

{

var time : String { get }

var title : String { get }

var content : String { get }

var url_title : String { get }

var store_title : String { get }

var buyNumber : String { get }

var phoneNumber : String { get }

}

protocol DrugAdviceTableViewCellDelegate

{

var timeFont: UIFont { get }

var titleFont: UIFont { get }

var contentFont: UIFont { get }

var timeColor: UIColor { get }

var titleColor: UIColor { get }

var contentColor: UIColor { get }

var buttonColor: UIColor { get }

}

这里利用了苹果定义tableView协议时的思想,dataSource是必须实现的协议,因为没有数据不知道该显示什么。delegate是可选协议,如果不现实我们应该有默认的实现效果。因为swift没有OC中的optional关键字,所以我们需要对DrugAdviceTableViewCellDelegate协议进行一个协议扩展。

extension DrugAdviceTableViewCellDelegate

{

var timeFont: UIFont { return SystemFont(AutoChangeSize(14)) }

var titleFont: UIFont { return SystemBordFont(AutoChangeSize(18)) }

var contentFont: UIFont { return SystemFont(AutoChangeSize(16)) }

var timeColor: UIColor { return UIColor.rgbColorWithHexString(BlackText666Color) }

var titleColor: UIColor { return UIColor.rgbColorWithHexString(BlackText333Color) }

var contentColor: UIColor { return UIColor.rgbColorWithHexString(BlackText333Color) }

var buttonColor: UIColor { return UIColor.rgbColorWithHexString("#2087fb") }

}

在cell里我们已经定义好的协议,接下来我们需要实现的就是一个ViewModel,在ViewModel里我们需要实现协议。

import UIKit

struct DrugAdviceViewModel: DrugAdviceTableViewCellDataSource {

var model: DrugAdviceModel? {

didSet {

time = model!.time!

title = (model?.title)!

content = (model?.content)!

url_title = (model?.url_title)!

store_title = (model?.store_title)!

buyNumber = model!.buyNumber!

phoneNumber = model!.phoneNumber!

}}  var time = ""

var title = ""

var content = ""

var url_title = ""

var store_title = ""

var buyNumber = ""

var phoneNumber = ""

}

extension DrugAdviceViewModel: DrugAdviceTableViewCellDelegate {

}

这里面的model是controller请求下来数据并转化为模型,传递给ViewModel的。至于为什么不在ViewModel里请求数据,因为我觉得请求下来的数据是一个数组,需要根据indexPath.row 根据不同行数显示不同的数据,所以还是放在controller里,保存为array,再根据indexPath.row传递给ViewModel比较好,也比较方便。

现在我们需要在controller里请求数据,并且需要根据不同的cell创建不同的ViewModel(ViewModel里的model的数据是不同的),并且把ViewModel传递给cell显示。

func getDurgAdvices()

{

AFNetWorkUtil.GET("recipe/notice", parameters: ["user_id" : GlobalInfo.sharedInfo.userInfo!.uid!, "page" : NSNumber(float: 1)], succeed: { (dataTask, responseObject) in

let datas: NSArray = responseObject["data"] as! NSArray

for dict in datas {

let model: DrugAdviceModel = DrugAdviceModel.parse(dict: dict as! NSDictionary)

self.durgAdvices?.append(model)

}self.tableView.reloadData()})                                                                   { (dataTask, error) in}}

// MARK: - tableViewDataSource

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return durgAdvices!.count

}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCellWithIdentifier("DrugAdvice", forIndexPath: indexPath) as! DrugAdviceTableViewCell

var viewModel = DrugAdviceViewModel()

viewModel.model = durgAdvices![indexPath.row]

cell.configure(withDataSource: viewModel, delegate: viewModel)

return cell

}

cell.configure(withDataSource: viewModel, delegate: viewModel)这个方法负责把ViewModel传递给cell。所以我们需要在cell里定义这个方法。最终cell的实现为:

import UIKit

protocol DrugAdviceTableViewCellDataSource

{

var time : String { get }

var title : String { get }

var content : String { get }

var url_title : String { get }

var store_title : String { get }

var buyNumber : String { get }

var phoneNumber : String { get }

}

protocol DrugAdviceTableViewCellDelegate

{

var timeFont: UIFont { get }

var titleFont: UIFont { get }

var contentFont: UIFont { get }

var timeColor: UIColor { get }

var titleColor: UIColor { get }

var contentColor: UIColor { get }

var buttonColor: UIColor { get }

}

extension DrugAdviceTableViewCellDelegate

{

var timeFont: UIFont { return SystemFont(AutoChangeSize(14)) }

var titleFont: UIFont { return SystemBordFont(AutoChangeSize(18)) }

var contentFont: UIFont { return SystemFont(AutoChangeSize(16)) }

var timeColor: UIColor { return UIColor.rgbColorWithHexString(BlackText666Color) }

var titleColor: UIColor { return UIColor.rgbColorWithHexString(BlackText333Color) }

var contentColor: UIColor { return UIColor.rgbColorWithHexString(BlackText333Color) }

var buttonColor: UIColor { return UIColor.rgbColorWithHexString("#2087fb") }

}

class DrugAdviceTableViewCell: UITableViewCell

{

@IBOutlet weak var time: UILabel!

@IBOutlet weak var title: UILabel!

@IBOutlet weak var content: UILabel!

@IBOutlet weak var buyNumber: UILabel!

@IBOutlet weak var buyButton: UIButton!

@IBOutlet weak var shopLocation: UIButton!

@IBOutlet weak var phoneNumber: UIButton!

private var dataSource: DrugAdviceTableViewCellDataSource?

private var delegate: DrugAdviceTableViewCellDelegate?

func configure(withDataSource dataSource: DrugAdviceTableViewCellDataSource, delegate: DrugAdviceTableViewCellDelegate?)

{

self.dataSource = dataSource

self.delegate = delegate

time.text = dataSource.time

title.text = dataSource.title

content.text = dataSource.content

buyNumber.text = dataSource.buyNumber

buyButton.setTitle(dataSource.url_title, forState: .Normal)

shopLocation.setTitle(dataSource.store_title, forState: .Normal)

phoneNumber.setTitle(dataSource.phoneNumber, forState: .Normal)

time.font = delegate?.timeFont

title.font = delegate?.titleFont

content.font = delegate?.contentFont

buyNumber.font = delegate?.contentFont

buyButton.titleLabel?.font = delegate?.contentFont

shopLocation.titleLabel?.font = delegate?.contentFont

phoneNumber.titleLabel?.font = delegate?.contentFont

time.textColor = delegate?.timeColor

title.textColor = delegate?.titleColor

content.textColor = delegate?.contentColor

buyNumber.textColor = delegate?.contentColor

buyButton.titleLabel?.textColor = delegate?.buttonColor

shopLocation.titleLabel?.textColor = delegate?.buttonColor

phoneNumber.titleLabel?.textColor = delegate?.buttonColor

}}

最主要的代码就是以上这些,运行后就能得到我们图2所示的效果。具体代码我放在了github地址,因为请求的方法里有一些参数是公司的,所以在分享的Demo里我使用的是自己写的数据,你只要把数据替换一下就可以。我们这个程序是适配不同屏幕的,所以对屏幕适配有问题的,可以参考一下。

相关文章

网友评论

    本文标题:在MVVM模式下基于协议开发Swift程序

    本文链接:https://www.haomeiwen.com/subject/lvbllttx.html