iOS MVVM最佳实践(一)

引言

  没有代码的瞎掰都是耍流氓!
  这里是我使用MVVM模式结合组件化所做的音乐类App小部分功能,包括歌单、搜索和播放。你可以在这里看到viewModel到底如何书写、如何与controller配合,组件化应该如何搭建等等细节。麻雀虽小五脏俱全,作为参照来讲应该是足够了的。
  这个系列是我在实践中的一些总结。学习之路上翻阅了不少博客,却都是介绍概念的居多,几乎没见着有完整代码供后来的人参考的。我遇到了很多坑也跨过了很多坑,所以有了写这几篇博客的动机。这几篇博客是配合我的代码来的,阐述了我是怎么做的、我为什么要这么做,当然我的做法不见得都是对的,只是希望能借此抛砖引玉。
  当然啦,基本的理论基础还是要有的,这第一篇先简单介绍一下。

什么是MVVM

  随着ReactiveCocoaRxSwift的横空出世,MVVM,这一发源于微软的软件架构模式也大热了起来,众多iOSer对此有着大量的讨论。
  我们先来看一眼MVC,Apple推荐的iOS App标准架构模式。

取自斯坦福公开课.png

  view将用户请求通知给controller,controller通过更新model来反应状态的改变,model(使用KVO和Notification)通知controller来更新他们负责的view。然而实际开发中充斥着大量如下代码:

class MyView: UIView {
  var model: MyModel? {
    didSet {
      // 在这里更新view的状态
    }
  } 
}

如此一来view和model就绑定在了一起,形成了紧耦合也就没有复用一说了。奇怪的是这种写法是那么的自然以至于大家都没有感觉到有什么不对劲~~
  再来看看MVVM:


取自微软MVVM介绍.png

MVVM是对MVC的一种改进。它将view和controller都视作view,view不持有model而是和viewModel通信,model的持有者变成了viewModel。在这个架构中viewModel接收用户请求处理业务逻辑并更新model,然后再将处理结果(也就是对model的更新)通过通知传回view来同步状态。使用MVVM能很好的分离UI和业务逻辑,view不持有model使得复用变成可能,viewModel因为不含任何UI元素因而能和任何view组合使用,同时对viewModel的测试也相对变得简单。
  MVVM是兼容于MVC的,你可以在项目中既使用MVC又引入MVVM,它对现有的代码并没有任何侵入性。所以少年,如果你还没有使用过MVVM,赶紧去试试吧,就像Swift一样,一旦上手了以后就再也回不去Objective-C了~~

Rx系列和MVVM的关系

  为什么Rx系列出现之前很少听说MVVM?Rx系列出现之后MVVM就受到如此推崇?难道说没有Rx系列的支持就无法使用MVVM?或者说MVVM是专门为Rx系列设计的?相信大家或多或少有着这样的疑问,这里推荐阅读iOS 关于MVVM Without ReactiveCocoa设计模式的那些事
  简而言之,iOS中可以使用Notification,KVO来实现绑定,只是过程比较痛苦(KVO不仅繁琐且回调略显蛋疼),而反观Rx系列,它使用观察者模式:

  • 可以方便的创建事件流和数据流
  • 使用查询式的操作符组合和变换数据流
  • 可以订阅任何可观察的数据流并执行操作

这就使得数据绑定变得极其简单。正是因为Rx系列完美契合于MVVM模式,所以才导致MVVM模式的大热。RxSwift和ReactiveCocoa因为高度类似,掌握其中一种足以。我这边使用的是RxSwift,这里安利两篇文档给不熟悉的小伙伴们:

什么是组件化开发

  一般我们在开发的时候都是新建一个Cocoa Touch Application,然后根据功能模块划分几个文件夹,比如Home/Discover/Profile/Vendor等等,这些文件夹又各自有着Controller/Model/Util之类的分层。看起来已经划分了功能模块,实际上这却是一个复杂的项目。所有的代码都在一个单一工程里,久而久之尤其是多人开发的时候,耦合会特别严重,你会发现去掉任何一个模块的代码,整个项目完全无法运行,并且即使你只想测试某个功能也不得不编译整个项目,组件化因此应运而生。
  对于组件化开发,我的理解就是将一个庞大臃肿的单一工程, 根据功能或者属性进行分解,拆分成各个独立的模块或者说是组件,这一步和之前其实没有区别,区别在于每一个组件都可以单独维护、独立运行,然后可以根据业务需求,组织成一个拥有完整业务逻辑的工程。;组件化特别适合大型项目的开发,因为:

  • 便捷性:仅仅通过改变依赖就可以进行功能的增减
  • 独立性:每个组件可以单独编写、单独编译、单独运行和单独测试
  • 复用性:对于功能性,工具性的代码亦或是通用的控件等等,可以很轻松的复用

如何组件化

  组件化带来的好处是非常直观的,并且它实现起来并不复杂,使用CocoaPods可以很方便的实现组件化。关于CocoaPods的基本使用相信大家都是十分熟悉的,这里就不介绍了。

pod lib create #ModuleName#

使用以上命令就可以在本地新建一个pod库。组件编写完以后你可以上传到远程服务器或者仅仅当作本地私有库使用。这里面唯一的坑点是集成第三方静态库,比如项目中使用到极光分享,在podsepc中写下:

s.dependency 'JShare'

会发现CocoaPods报错。

The 'Pods-xx' target has transitive dependencies that include static binaries

解决的办法在这里。简单来说就是我们新建一个Cocoa Touch Framework来包装这个静态库就可以。如果你也遇到了这个问题,这篇文章应该能够帮到你。

组件化中间层如何实现

  设计组件化中间层有两种比较有代表性的方案:

  两种方式我都有尝试过,谈一点个人看法吧。URL注册的方式在使用上非常繁琐而且很多时候其实没有必要。首先每一个页面跳转都需要事先注册好URL,这里会牵涉到非常多字符串硬编码,很容易出错;其次两个有强关联的页面,比如从预览到详情,这两个页面总是会成对出现,你几乎没有其他选择会跳转其他页面,这种情况下个人感觉注册不注册URL都没有什么关系。基于runtime的Mediator方式,首先它不需要注册,省去了很多比对字符串的过程,当然,这种方式依然避免不了字符串硬编码,不过体量相对较小;其次它可以非常容易的传递各种参数来进行组建间通信。
  我选择的是Mediator方式,也因为它易于实现,在模块的划分上我的做法粒度比较大,这些具体在代码里体现。

总结

  以上简要介绍了MVVM和组件化开发,我这里就说这么多了,接下来是show you the code环节。需要说明的是这是一份Swift代码,并且使用了RxSwift,如果你对这些都不熟悉,可能这个暂时还不太适合你。使用ReactiveCocoa的同学不要慌,首先RxSwift和ReactiveCocoa区别真没那么大,再者这里讲的是如何做,和使用的库关系不大,套用一下即可。
  下一篇讲的是代码逻辑,喜欢看干货的同学不要错过了哟。这里再次安利一下代码地址,如果觉得有帮助,点个star呗,又不会怀孕不是~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358