乐趣区

关于ios:iOS组件化

Vue 组件化 与 iOS 的业务组件化(模块化)

iOS 组件化 Modular

Vue

一. 组件化的需要

Vue.js 的两个外围数据驱动和组件化

为了进步代码复用性,缩小重复性的开发,咱们就把相干的代码依照 template、style、script 拆分,封装成一个个的组件。组件能够扩大 HTML 元素,封装可重用的 HTML 代码,咱们能够将组件看作自定义的 HTML 元素。

二. 如何划分组件

通常一个利用会以一棵嵌套的组件树的模式来组织:

三. 组件分类

组件的品种可分为以下 4 种:

  1. 一般组件
  2. 动静组件
  3. 异步组件
  4. 递归组件

一般组件

import tem from './components/tem' 
...
{components: {tem}  // 注册
}

动静组件

var vm = new Vue({
  el: '#example',
  data: {currentView: 'home'},
  components: {home: { /* ... */},
    posts: {/* ... */},
    archive: {/* ... */}
  }
})
<component v-bind:is="currentView">
  <!-- 组件在 vm.currentview 变动时扭转!-->
</component>

异步组件

const AsyncComponent = () => ({// 须要加载的组件 (应该是一个 `Promise` 对象)
    component: import('../components/MyComponent'),
    // 异步组件加载时应用的组件
    loading: LoadingComponent,
    // 加载失败时应用的组件
    error: ErrorComponent,
    // 展现加载时组件的延时工夫。默认值是 200 (毫秒)
    delay: 200,
    // 如果提供了超时工夫且组件加载也超时了,// 则应用加载失败时应用的组件。默认值是:`Infinity`
    timeout: 3000
})

递归组件

name: 'recursion-component',
template: '<div><recursion-component></recursion-component></div>'

iOS

注:对于 iOS 或者 android 相比组件(Component),个人感觉称之为模块(Module)更为适合。组件强调物理拆分,以便复用;模块强调逻辑拆分,以便解耦。而且如果用过 Android Studio, 会发现它创立的子系统都叫 Module. 但介于业界习惯称之为组件化,所以咱们持续应用这个术语。链接

一. 组件化的需要

在 iOS Native app 后期开发的时候,如果参加的开发人员也不多,那么代码大多数都是写在一个工程外面的,这个时候业务倒退也不是太快,所以很多时候也能保障开发效率。然而一旦我的项目工程宏大当前,开发人员也会逐步多起来,业务倒退突飞猛进,这个时候繁多的工程开发模式就会暴露出弊病了。

  • 我的项目内代码文件耦合比较严重
  • 容易呈现抵触
  • 业务方的开发效率不够高

为了解决这些问题,就呈现了组件化的概念。所以 iOS 的组件化是为了解决上述这些问题的,这里与 Vue 组件化解决的痛点不同。

iOS 组件化当前能带来如下的益处:

  • 放慢编译速度(不必编译主客那一大坨代码了,各个组件都是动态库)但动态库会加大包体积的大小
  • 不便 QA 有针对性地测试
  • 进步业务开发效率

组件化的封装性只是其中的一小部分,更加关怀的是如何拆分组件,如何解除耦合。前端的组件化可能会更加重视组件的封装性,高可复用性。

二. 如何封装组件

iOS 的组件化伎俩十分繁多,就是利用 Cocoapods 封装成 pod 库,主工程别离援用这些 pod 即可。最终想要达到的现实指标就是主工程就是一个壳工程,其余所有代码都在组件 Pods 外面,主工程的工作就是初始化,加载这些组件的,没有其余任何代码了。

拿弹个车为例

CocoaPods,iOS 包管理工具,相似于前端的 npm, yarn。其原理:依据 Podfile 形容,找到对应代码库的 podspec 文件,而后依据 podspec 中的形容,找到代码库,并且找到之后,拷贝须要的文件到本人的工程中。具体如果用 Cocoapods 打包一个动态库 .a 或者 framework 链接

三. 如何划分组件

iOS 划分组件尽管没有一个很明确的规范,因为每个我的项目都不同,划分组件的粗粒度也不同,然而仍旧有一个划分的准则。

App 之间能够重用的 Util、Category、网络层和本地存储 storage 等等这些货色抽成了 Pod 库。还有些一些和业务相干的,也是在各个 App 之间重用的。

准则就是:要在 App 之间共享的代码就应该抽成 Pod 库,把它们作为一个个组件。不在 App 间共享的业务线,也应该抽成 Pod,解除它与工程其余的文件耦合性。

常见的划分办法都是从底层开始入手,网络库,数据库存储,加密解密,工具类,地图,根底 SDK,APM,风控,埋点……从下往上,到了下层就是各个业务方的组件了,最常见的就相似于购物车,我的钱包,登录,注册等。

四. 组件间的消息传递

划分好了组件,那么咱们就要解决两个问题:1. 各个页面和组件之间的跳转问题。2. 各个组件之间互相调用。

iOS 组件化有以下三种计划

  • URLRouter 注册
  • Protocol-Class 注册
  • Taret-Action

咱们公司的计划是 Target_Action,但体现上Target_Action 能够通过 URL 来体现,也就是说 URL 通过解析能解析成 Target_Action 的模式。

1.url-block

url-block 这个形式我最早是在蘑菇街的组件化计划中看到的,简略来说它就是配置“一段 url 对应一个 block 办法”,当咱们应用 openUrl:办法的时候,其实就是在调用这个 block 办法。

比方上面代码:

[MGJRouter registerURLPattern:@"mgj://detail?id=:id" toHandler:^(NSDictionary *routerParameters) {NSNumber *id = routerParameters[@"id"];
    // create view controller with id
    // push view controller
}];

这是蘑菇街调用详情页的办法,MGJRouter作为中间件,任何组件间的调用都有它来对立解决。不过这种 url 的传递形式使得参数类型受到了限度,无奈传递非常规的参数类型,比方 UIImage。于是就有了上面这种 protocol-class。

2.protocol-class

protocol-class 也是在蘑菇街组件中提出的,对于须要非常规参数的时候,他们就应用这种计划。protocol-class 通过在外部保护了一个 protocol 和 class 的映射表,依据对于的 protocol 来获取对应的 class,应用方不须要在意 class 是哪个类,只有晓得它实现了 protocol 就能够。

代码如下:

[ModuleManager registerClass:ClassA forProtocol:ProtocolA];
[ModuleManager classForProtocol:ProtocolA];

[ModuleManager classForProtocol:ProtocolA] 的返回后果就是之前在 ModuleManager 外部注册好的 dict 里 protocol 对应的 class。

3.target-action

这种组件化形式是利用一个中间件来调用,中间件利用 runtime 来调用其余组件,这种形式能够做到真正意义上的解耦。而后再通过实现中间件 category 的形式来提供服务,使得使用者只须要依赖中间件,而组件不须要依赖中间件。

外围代码总结

[self performTarget:@"A" action:@"viewController" params:params shouldCacheTarget:NO];
// 这里的类和办法子都是运行时动静生成的
- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget
{if (targetName == nil || actionName == nil) {return nil;}
    NSString *swiftModuleName = params[kCTMediatorParamsKeySwiftTargetModuleName];
    // generate target
    NSString *targetClassString = nil;
    if (swiftModuleName.length > 0) {targetClassString = [NSString stringWithFormat:@"%@.Target_%@", swiftModuleName, targetName];
    } else {targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
    }
    NSObject *target = [self safeFetchCachedTarget:targetClassString];
    if (target == nil) {Class targetClass = NSClassFromString(targetClassString);
        target = [[targetClass alloc] init];
    }
    // generate action
    NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
    SEL action = NSSelectorFromString(actionString);
    .......
}

4.AppDelegate 解耦

典型的解决方案有以下几种:

• plist 动态注册

• load 办法动静注册

• 基于__attribute__的 clang 语法,把注册信息写到 mach- o 文件里 美团计划 facebook 计划 案例

两者平台上开发方式存在差别

次要体现在单页利用和类多页利用的差别。当初前端比拟火的一种利用就是单页 Web 利用(single page web application,SPA),顾名思义,就是只有一张 Web 页面的利用,是加载单个 HTML 页面并在用户与应用程序交互时动静更新该页面的 Web 应用程序。

浏览器从服务器加载初始页面,以及整个利用所需的脚本(框架、库、利用代码)和样式表。当用户定位到其余页面时,不会触发页面刷新。通过 HTML5 History API 更新页面的 URL。浏览器通过 AJAX 申请检索新页面(通常以 JSON 格局)所需的新数据。而后,SPA 通过 JavaScript 动静更新曾经在初始页面加载中曾经下载好的新页面。这种模式相似于原生手机利用的工作原理。

然而 iOS 开发更像类 MPA (Multi-Page Application)。

往往一个原生的 App,页面差不多应该是上图这样。

两者解决的需要也存在差别

iOS 的组件化一部分也是解决了代码复用性的问题,然而更多的是解决耦合性大,开发效率合作性低的问题。而 Vue 的组件化更多的是为了解决代码复用性的问题。

两者的组件化的方向也有不同。

iOS 平台因为有 UIKit 这类苹果曾经封装好的 Framework,所以根底控件曾经封装实现,不须要咱们本人手动封装了,所以 iOS 的组件着眼于一个大的性能,比方网络库,购物车,我的钱包,整个业务块。前端的页面布局是在 DOM 上进行的,只有最根底的 CSS 的标签,所以控件都须要本人写,Vue 的组件化封装的可复用的单文件组件其实更加相似于 iOS 这边的 ViewModel。

集体实现的一个组件化小 Demo
Modular 喜爱的给个 start

友情链接:
Vue.js 官网文档

组件化 OR 模块化

iOS 组件化 —— 路由设计思路剖析

iOS 利用架构谈 组件化计划

App 组件化与业务拆分那些事

退出移动版