iOS 响应式架构设计方案

  • 网站建设 2019-05-01
<返回列表

分享数:2

  iOS 响应式架构设计方案
1.响应式编程是一种和事件流有关的编程模式,关注导致状态值改变的行为事件,一系列事件组成了事件流。
2.一系列事件是导致属性值发生变化的原因。FRP非常类似于设计模式里的观察者模式。

3.FRP与普通的函数式编程相似,但是每个函数可以接收一个输入值的流,如果其中,一个新的输入值到达的话,这个函数将根据最新的输入值重新计算,并且产生一个新的输出。这是一种”数据流”编程模式。


  iOS 响应式架构设计方案


   iOS 响应式编程优势;
1,开发过程中,状态以及状态之间依赖过多,RAC更加有效率地处理事件流,而无需显式去管理状态。在OO或者过程式编程中,状态变化是最难跟踪,最头痛的事。这个也是最重要的一点。

2, 减少变量的使用,由于它跟踪状态和值的变化,因此不需要再申明变量不断地观察状态和更新值。

3, 提供统一的消息传递机制,将oc中的通知,action,KVO以及其它所有UIControl事件的变化都进行监控,当变化发生时,就会传递事件和值。

4, 当值随着事件变换时,可以使用map,filter,reduce等函数便利地对值进行变换操作。

设计一个简单的 iOS 响应式架构。iOS 架构 DEMO
关于组件化;
组件化似乎是项目发展壮大过后必然要做的事情,它能让各个业务线的工程师不需要过多的关注其他业务线的代码,有效的提高团队整体效率。然而实施组件化的时机是在需求相对稳定、产品闭环形成过后。所以本文不会应用组件化,但是这里简单谈谈业界的组件化方案。
组件化的核心问题就是组件间如何通讯。“软件工程的一切问题都能通过一个间接的中间层解决。”中介模式很自然的运用起来:
这样虽然能统一组件间的通讯请求,但是却没有避免 Mediator 和目标组件的耦合,ModuleA 工程中仍然需要导入 ModuleB 

所以重点问题落在了解耦上:

要达到 Mediator 和目标组件的解耦,就需要实现它们之间的间接调用(图中虚线),既然是间接调用,必然需要一种映射机制。在 iOS 开发中,业界大概有三种方式来处理。
(1) 使用 URL -> Block 解耦

简单来说就是将组件的调用代码放入 block 中,然后 URL 作为 key,block 作为 value,存入一个全局的 hash 容器,组件通过一个 URL (比如 “native/id=10/type=1” )向 Mediator 发起请求,Mediator 找到对应的代码块执行。由此,解开了 Mediator 和目标组件的耦合(见博客:蘑菇街 App 的组件化之路)。

这种方案的缺陷很多:组件越多常驻内存越多;解析 URL 逻辑复杂;URL 无法表述具体语言相关的对象类型。所以这种方式并不适合组件化解耦。
(2) 使用 Protocol 解耦

阿里的 BeeHive 是该方案的很好实践,笔者阅读了一下源码,它的大致工作原理如下:注册 Protocol 对应的组件,这个和上面说的 URL->Block 方式如出一辙,只不过这里是 Protocol-> Module ;组件申请访问时导入对应的 Protocol 通过 Mediator 获取到对应的组件对象。由于协议的表述能支持所有的对象类型,所以这种方式能基本解决组件间通信的需求。

BeeHive 注册组件有几种方式,一种是监听了动态链接时 image 二进制文件加载完成的回调,通过修改代码段的方式判断对应的模块进行注册;第二种是在 +load 方法里面注册;第三种是异步注册,但是这种方式存在一个问题,可能组件使用方准备使用组件的时候,这个组件还未注册成功。

BeeHive 还为组件设置了优先级的概念,它通过数组来保持优先级排序,在源码中能看到一些数组排序的逻辑,这就带来了相当多的高时间复杂度的运算。

所以,组件数量过多的话,会延长动态链接库的过程。

BeeHive 为了让每一个组件享有独自的 app 生命周期、3D touch 等功能,会将这些系统级的事件发送给每一个组件,且不谈大量的方法调用损耗,它必须让入口文件 AppDelegate 继承自 BeeHive 的 BHAppDelegate,笔者感觉侵入性过强,并且当开发者需要复写 AppDelegate 方法的时候,还要注意让super调用一下,可以说很不优雅了。

在基于协议的组件化方案中,组件使用方能直接拿到目标组件的实例,那么使用者可能对该实例进行修改,这可能会带来安全问题。
(3) 使用 Target-Action 解耦

Casa Taloyum 前辈的 iOS应用架构谈 组件化方案 为此做出了最佳实践。

Mediator 使用 Target-Action 来间接的调用目标组件,无需专门注册。组件维护者需要做一个 Mediator 的分类,通过硬编码调用目标组件,然后组件使用者只需要依赖这个分类就行了。封装的 Mediator 源码只有简单的 200+ 行代码,并且很易懂。这也让开发者能对组件化的实施更加有信心,不会因为基础设施的错误而束手无策。
小总结

关于以上组件化的简单表述仅代表笔者的个人见解,由于笔者并没有真正的实施组件化,所以理解可能有误。
虽然笔者设计的 iOS 架构不会应用组件化,但是这给我们的架构设计带来了前瞻性的引导,这非常重要。

模块化思维划分文件;

在团队开发中,项目发展到后期总是会出现某些文件或代码难以管理,出现这种情况的主要原因通常是项目开发过程中对文件的管理过于随意。
开发者应该尽量将所有代码文件归于模块,而不要出现模拟两可的文件。而笔者这里说的模块,是有具体意义的模块,比如图片处理模块、字体处理模块,而不是诸如 Public、Common 等无具体意义的代码文件。

试想,在多人开发中,当所有人都觉得有些代码不知道怎么归类的时候,就会往 Public 里面扔。当你某天想要整理一下这个 Public,会发现已经无从下手;或者当你需要迁移项目中的某个业务模块时,会附带迁移一些模块,当这个模块是有意义的(比如图片处理模块),你的迁移成本会非常低,但是当这个藕断丝连的模块是 Public 时,时间成本可能高于你的想象,估计你会将它完整的拷贝过去,而又对新项目造成了污染。

全局的公共文件是产生垃圾代码的源头。笔者认为几乎所有的代码都是可以归类为模块的。

大致梳理了一个文件分类,当然这个分类是灵活的,只是要分模块划分:

  - GeneralModules 放项目独有的通用配置模块(比如通用颜色模块、通用字体模块)  
  - ToolModules 放工具类模块(比如系统信息模块) 
  - PackageModules 放基于业务的一些封装(比如提示框模块、加载菊花模块) 
  - BusinessModules 放业务模块(比如购物车、个人中心)

具体里面放了些什么,可以查看笔者的 DEMO。

减少全局宏的使用;
很多时候,过多的宏让项目很不整洁,每一个开发者都往全局文件添加宏,而往往只是一段简单的代码,笔者认为开发中应该尽量少使用宏,原因如下:

    宏在预编译阶段替换为实际代码,存在效率问题
    使用宏的地方可能只需要一块内存,但是宏替换过后开辟了多个(这种情况应该用常量替换宏)
    可能存在潜在的宏命名冲突
    宏包装过多的代码难以理解和调试
    代码迁移时需要处理全局的宏

实际上,非得使用宏的地方并非那么多,比如需要定义一个全局的导航栏字体方便使用,可以将通用字体的配置参数作为一个模块:

@interface HQGeneralFont : NSObject
/** 导航栏标题字体 */
+ (UIFont *)navigationBarTitleFont;
@end

或者用常量来代替宏:

.h
FOUNDATION_EXTERN NSString * const kNotify_xxx; 
//xxx通知 key.m
NSString * const kNotify_xxx = @"kNotify_xxx";

这么做也便于转换思维,毕竟 swift 中是没有宏的。

  iOS 响应式架构设计方案

更多阅读

SEO解决方案主要是根据哪些内

诊断教程 2020-06-11
SEO解决方案主要是根据哪些内容来改善?现在有很多企业都会非常重视网站这一......查看全文

百度关键词优化一般都要做什

诊断教程 2020-06-11
百度关键词优化一般都要做什么事情?现在有非常多人都很关心互联网上的信息......查看全文

关键词优化SEO有什么样的考核

诊断教程 2020-06-11
关键词优化SEO有什么样的考核指标?关键词优化SEO在进行实际考核的过程当中将......查看全文
返回全部新闻
扫描二维码分享到微信
确 认
友情链接: SEO 米菲纸尿裤 百度刷排名