关于“幽灵架构”的总结:适用场景与方法重载

前几篇博文对“幽灵架构”做了用法的介绍和相关技术点的补充,本文是一篇总结性质的文章,分析该架构的适用场景和限制,首先让我们回顾一下iOS开发的MVC模式,参考斯坦福公开课里Paul老爷子的讲解,如下图所示:
这里写图片描述
在MVC模式下Model和View是不能直接通信的,在“幽灵架构”体系中Model和View依旧不能直接通信,在传统的MVC中,这种通信的阻隔很多时候是因为在没有得到Model和View实体的情况下无法完成二者的数据绑定,在过去你可能想过在View中写一个方法来接受一个模型,然后写具体的实现,在没有泛型的帮助下只能用方法的重载来做,没有协议扩展的情况下需要在父类和写重复的代码中做选择。
在“幽灵架构”体系中,通过ModelType和ViewType可以在不借助控制器的帮助下实现二者的逻辑绑定,依旧是使用了方法传值的用法,Controller起到了“开关”的作用,依靠泛型和协议对数据类型进行了约束,并且避免了重复代码,不需要在意数据源的同构和异构。
我们需要在Controller中创建Model和View的实例,并且和MVC一样可以对Model和View做处理,但是Model和View之间的逻辑关系是定义在View的getData中的,比如Demo中Event的Cell会被标注为红色,如果要通过修改Controller的标志位来影响Model和View之间的逻辑,比如Demo中在Controller中加入一个开关,点击后会互换Event和Festival的背景色,这就属于Controller中引入了标志位来影响View和Model的逻辑,此时如果要继续维持“幽灵架构”的体系,那么需要重载giveData和getData方法,传入Controller中的标志位。首先给getData增加默认实现,因为在View的代码中我们只想重写需要的重载的方法:

//视图使用的协议
protocol ViewType{
    func getData<M:ModelType>(model:M)
}
//数据使用的协议
protocol ModelType{
}
//定义默认方法giveData
extension ModelType{
    func giveData<V:ViewType>(view:V){
        view.getData(self)
    }
}
extension ViewType{
    func getData<M:ModelType>(model:M){

    }
}

为了维持“幽灵架构”的灵活性,我们重写了giveData和getData,不是在具体的遵守者中重写,而是直接扩展协议:

extension ModelType where Self:HasDate{
    func giveData<V:ViewType>(view:V,tag:Bool){
        if let tableCell = view as? ShowedTableViewCell{
            tableCell.getData(self,tag:tag)
        }
    }
}

extension ViewType where Self:ShowedTableViewCell{
    func getData<M : ModelType>(model: M,tag:Bool){

    }
}

现在不需要修改所有的Model,但是需要在View中重写新定义的方法:

func getData<M : ModelType>(model: M,tag:Bool) {
        //这里不能写成guard let dateModel = model as? DateViewModel else{}令我有些意外
        guard let dateModel = model as? HasDate else{
            return
        }
        //处理相同属性
        dateLabel.text = dateModel.date
        //处理数据源异构
        if let event = dateModel as? Event{
            MixLabel.text = event.eventTitle
            backgroundColor = tag  ? UIColor.redColor():UIColor.whiteColor()
        } else if let festival = dateModel as? Festival{
            MixLabel.text = festival.festivalName
            backgroundColor = !tag  ? UIColor.redColor():UIColor.whiteColor()
        }
    }

这是协议扩展的另一个神奇之处:不会引入多余的状态,避免了“上帝类”的出现,如果你的工程中有其他的Model和View的绑定,不会受到任何影响。最后一步,修改Controller中的数据绑定:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(cellReusedID, forIndexPath: indexPath) as! ShowedTableViewCell
        //调用重载的方法
        dataList[indexPath.row].giveData(cell,tag:true)
        return cell
    }

现在尝试向tag传入true和false看看效果吧:
这里写图片描述
tag传入false
这里写图片描述
tag的值取决于Controller,从上面的例子中看出在Controller中切换View和Model的绑定逻辑是完全没问题的。之前讲过giveData方法是为了在异构数据源中避免Box类型的出现,提高运行效率,针对同构的数据源,我们只需要重载getData并在控制器中直接使用getData对数据进行捆绑就好了。
所以,我之所以在最初的文章中称“幽灵架构”为MV,其实并没有弱化控制器的职责,但是把控制器中有关于模型和视图逻辑绑定的代码移到了View中,并且集中在了getData一个方法中,便于维护,为控制器减压,所以其实这是一个“伪架构”。从上面的示例中可以看到,MVC和MVVM能做到的“幽灵架构”一样能做到,并且比MVC中控制器的代码更好维护,比MVVM少写了很多代码。“幽灵架构”今后的发展,需要经历时间的考验了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值