简介

MIST 是口碑团队研发的一套高性能的 iOS 动态化解决方案,2016年最初被用于开发支付宝 App 的 O2O 业务,因其开发速度快,无需发版的特性迅速得到了众多业务团队的青睐。MIST 经历了日常百万 UV 的考验,在双 12 等大型活动中经历了千万 UV 的洗礼,目前已经足够稳定,部分代码已经开源。本人(kyson.cn)在蜂鸟配送个人中心页面使用了 MIST 技术。

MIST

需要注意的是,饿了么内部使用的 MIST 和对外开源的版本差别比较大,后者目前处于几乎无人维护的阶段。如果贵公司没有足够的人手,不建议大家贸贸然上 MIST。

尽管如此,也不建议大家立刻停止阅读接下来的内容,MIST 的代码还是有一定的研究价值的————他的可以实现 H5 来编写 iOS 界面,这点类似 Android 的 XML。相信很多 iOS 开发人员都很羡慕 Android 的 XML,他的效率比 iOS 的 Hard Code 高多了。

MIST 的另外一个特性是支持动态下发。他只需要一个 json 文件就可以渲染整个页面,我们只需要把 json 放在服务器,在合适的时间下发到本地即可。

废话不多说,我们现在就开始研究一下他!

集成

MIST 的 github 地址在这里:https://github.com/Vizzle/MIST,我们注意一下这个 Vizzle 用户,他下面还有几个仓库分别是:

  • VZFlexLayout : MIST 的底层实现
  • Vizzle : iOS MVC Framework
  • mistcmistc: MIST 组件编译工具

编译运行

git clone 到本地后,目录如下:

目录

双击 MIST-Demo.xcworkspace打开工程,编译运行,我们可以在模拟器或者真机上看到主页面:

MIST Demo 主页面

代码分析

我们先看一下仿微博 timeline 这个 demo:

仿微博 timeline

然后看代码实现(WBTimelineListViewController 中的 load 方法):

- (void)load
{
    [[MistDemoTemplateManager defaultManager] downloadTemplates:@[@"WeiBo"] completion:^(NSDictionary<NSString *,NSString *> *templates) {
        NSString *path = [NSString stringWithFormat:@"%@/mist.bundle/WeiBo.json", [NSBundle bundleForClass:self.class].bundlePath];
        NSData *rawData = [NSData dataWithContentsOfFile:path];
        NSDictionary *data = [NSJSONSerialization JSONObjectWithData:rawData options:NSJSONReadingAllowFragments error:nil];
        self.data  = [data[@"statuses"] copy];
        self.items = [self itemsWithData:self.data templates:templates];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
        
    } options:nil];
}

可以看到其主要是加载了本地的 WeiBo.json 文件,为了验证UI数据是否来自该文件,我们把 “新浪科技” 改成 “kyson.cn”, 重新编译看一下效果:

改 json

果不其然,用户名改了,这验证了我们的第一个假设: UI的数据来自 json 文件

接下来,我们进入MistDemoTemplateManagerdownloadTemplates 方法内部,一探究竟:

//@Important! If using the local templates, this method will be hooked by MistDebugger
- (void)downloadTemplates:(NSArray *)tplIds completion:(void (^)(NSDictionary<NSString *, NSString *> *templates))completion options:(NSDictionary *)opt
{
    __block NSMutableDictionary<NSString *, NSString *> *results = [NSMutableDictionary dictionary];
    __block NSInteger count = 0;
    for (NSString *tplId in tplIds) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSString *tplPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"mist.bundle/%@", tplId] ofType:@"mist"];
            NSString *result = [[NSString alloc] initWithContentsOfFile:tplPath
                                                               encoding:NSUTF8StringEncoding
                                                                  error:nil];
            dispatch_async(dispatch_get_main_queue(), ^{
                ++count;
                [results setObject:result forKey:tplId];
                if (count == tplIds.count) {
                    if (completion) {
                        completion(results);
                    }
                }
            });

        });
    }
}

不难发现,他加载了 WeiBo.mist 文件。同样的,我们改一下 WeiBo.mist 文件的内容,也不难发现, UI 的布局来自 mist 文件

总结

FlexBox布局算法:MIST内部实现了CSS3 FlexBox的标准布局算法,作为模板布局的核心能力;对比现有的FlexBox算法(RN, Weex), MIST支持的属性更完整,灵活性更高 ;算法采用C语言实现,无运行时的性能损耗

高效的语法解释器:MIST内部实现了一套功能完备的语法解释器,支持基本的数学运算、逻辑运算、比较运算、条件表达式等;此外,MIST还支持OC类方法的调用作为对Native通信能力的补充

UI异步绘制:MIST对UI底层渲染做了深度优化,对模板内的UI元素支持整体的异步光栅化绘制,可以极大的提升FPS,使页面具有更流畅的滑动体验

React:MIST将React.js的思想移植到了客户端,使用Objective-C++实现了一套Native版本的React。因此MIST底层也具备和React相似的运作机制,包括Virtual Dom结构,使用Immutable数据和One-Way data flow等。MIST模板在此之上进行了一层抽象,使开发者不需要理解上述概念,也不需要关心具体的实现细节,降低上手门槛