iOS中的行为

开场白

8月份的时候由于我们项目急招人,就跟着去面试了一段时间,发现在问到使用过的设计模式时,大部分都说的是代理模式、观察者模式、工厂模式…。今天就来介绍一个模式——行为模式,了解一下,至少在以后的面试中答出一点新鲜的东西也是好的😉。objccn.io的这篇iOS中的行为已经讲解的非常详细了,可以作为一个入门的学习。我这里再额外举一些例子,对我在读这篇文章时一些感到疑惑的地方用代码做个实际演示。

进入主题

行为是一个负责实现一个指定功能的对象,在iOS中就是一个封装了特定功能,继承于NSObject的普通对象。运用行为,实际上就是组合模式,将每个不可再划分的功能模块单独封装起来,然后再通过一定手段组装起来。这样的设计至少有以下点好处:

  • 能大大减少ViewController中的代码
  • 能让你0代码的去集成一个功能
  • 能让设计和产品自己去调整效果
  • 能提高代码的可复用性和可测试性

减少ViewController中的代码是自然的啦,对于职责单一的功能自然也是容易复用和容易测试的,那对于第2点和第3点怎么做到的呢?那就是借助IB中一个强大的但是经常被忽略的功能,Object这个控件。同时借助在IB中设置运行时属性,达到可视化编程。对于StoryBoardXib都有这个控件。

Talk is cheap, Show me the code,演示的demo:https://github.com/shinancao/BehaviorDemo

这里面举了几个例子,是目前我能想到的行为可以应用到的场景。

基础行为的构建

  • ImagePickerBehavior

点击一个按钮,弹起选项,然后调起系统相册或相机。这个是非常简单的功能了,你可以通过这个了解IB中Object这个控件怎么用。操作一遍后你会发现,真的无须写一行代码就能让你的应用成功集成这个功能。

  • CheckCodeBehavior

在文本框中输入内容,如果符合电话号码则发送验证码的按钮会亮起来,点击发送后,按钮变为不可用,然后开始倒计时。发送验证码的样式完全在IB中可配置。通过这个例子,可以了解到我们在IB中可以定义的运行时属性其实非常的丰富,上面的那张截图正是来自这个例子。

在这个例子中还有一个特别要注意的技巧,就是按钮被点击时,要通知ViewController去真正的向服务器发送请求发一个验证号码给用户。那怎么通知呢?可以让CheckCodeBehavior继承自UIControl,通过调用sendActions(for: .touchUpInside)手动触发CheckCodeBehavior的点击事件,然后把这个点击事件连接到ViewController中,这样就可以啦。这个技巧在设计行为时非常有用,让你的行为继承UIControl

组合行为(多路代理)

  • BackgroundGradientBehavior + NavBarGradientBehavior

在滑动列表时,导航栏会由透明变成紫色,同时背景也会逐渐变模糊。这两个行为都需要用到UIScrollViewdelegate方法,而代理通常又是一对一的关系,那如何将每个行为分离开呢?可以用消息来实现多路代理,具体的代码在Demo有。这样就不用在UIScrollViewdelegate方法中写长长的代码了,要做的功能拆分到每个行为中去。

不一定非得用IB才能做,用代码一样也可以实现多路代理,有可能你的App已经比较成熟了,而且一开始并不是用IB做的,也可以试试的。

剥离布局和布局展示的逻辑

  • GoodsDetailBehavior

像商品详情界面,若不需要用UITableView来实现,而是直接用多个view布局的。通常有两种做法:

  1. 直接将控件连到Controller中,但会使Controller变得臃肿。
  2. 用一个BoxView将所有的小控件放进去,然后Controller只与其交互。但在数据展示前通常要做一些逻辑处理,实质上干了控制层应该干的事。而且不能直接在StoryBoard上的Controller中直接布局了。

第1点显示是很糟糕的做法,对于第2点我也一直耿耿于怀,因为让在View里干了Controller要做的事儿,所以学习行为时,觉得行为能够解决这个问题。但仔细想了想还是有一些问题,就是有可能导致ViewControllerBehavior频繁的互调通信,如果这两部分耦合这么强烈,那拆分就没啥意义了。

这也是我的一个思考吧,实际开发中我还没有这样用过。后来接触到了一个架构模式VIPER,可以让View中不去处理那么多逻辑。但是使用下来也有些其他的问题,以后再另外写文章总结啦。

行为的生命周期

在Interface Builder中创建的行为,如果没有另外的对象对其引用,它将会在被创建后立刻移除。如果真的需要该行为常住,也尽量不要将行为定义成Controller的一个属性。这有可能导致行为与Controller过多的耦合,而且当不需要这个行为时,还要在Controller中去清除这个行为。可以通过Objective-C运行时将行为与Controller进行绑定,Demo中有演示。

下一篇文章说了一下给这些Behavior写单元测试的一些感受~

参考链接

介绍行为相关的

https://www.objc.io/issues/13-architecture/behaviors/

https://github.com/zziking/KIZBehavior

涉及到动画实现的

http://five.agency/how-to-create-an-interactive-blur-effect-in-ios8/

https://github.com/ltebean/LTNavigationBar

转载请注明出处:

作者:意林

原文链接:http://shinancao.github.io/2017/01/08/iOS-Behavior/

–End–