写点什么

Swift 在好大夫 APP 医患两端的打怪升级

  • 2020-09-23
  • 本文字数:3217 字

    阅读完需:约 11 分钟

Swift在好大夫APP医患两端的打怪升级

swift 作为苹果的亲儿子,从 2014 年开始,在 6 年的发展过程中,终于在 2019 年 3 月份迎来了 ABI(Application Binary Interface)的稳定。

背景

ABI 的稳定意味着 Binary 接口稳定,也就是运行的时候只要是通过 swift 5 或者以上的编译器编译出来的 binary,就可以跑在任意的 swift 5.0 及以上的 runtime 上。这样,我们就不需要像以前那样在 app 里面放一个 swift runtime,Apple 会把相应的 ABI 整合到 iOS 或者 macOS 中。同时 App 的尺寸会变小,在 iOS12.2 以上系统,会预装 swift 5 runtime,所以不在需要swift的库,它们会从 app bundle 中被删除,对于 iOS12.2 以下的系统,还是照旧需要引入。同时因为系统集成了 swift,app 启动的时候也就不需要额外加载 swift,在新系统中会更加的节省内存空间。


对于好大夫的医患两端,在这时接入 swift 是一个不可多得的好机会。那么,从好大夫的 iOS 客户端团队角度出发,接入 swift 需要有哪些准备工作?基础框架如何设计?如何解决在 swift 开发中出现的问题?这些都会在下文中一一解答。

接入 swift 的准备工作

好大夫的 iOS 客户端代码年份非常久远,整体使用 Objective-C 编写,最早的代码可以追溯到 2011 年 8 月份,对于接入 swift 来说,首先需要进行技术调研,什么版本的 swift 适合好大夫客户端,而不是一味的追求最新的 swift 版本。其次,对于 swift 三方框架的调研,国内的 swift 社区活跃度并不是特别高,相反国外的 swift 社区反而更加的活跃,从 github 上的 Alamofire 网络库到Uber早已使用 swift 重构客户端,可见 swift 在过国外早已盛行已久。


通过调研,swift 在开发效率和性能上明显优于 Objective-C,苹果开发者官网上各种 Programming Guide 也已经以 swift 作为首要显示语言,从苹果对 swift 的推广来看,如果我们一直坚守 Objective-C 阵营,在未来苹果强制推进 swift,对我们来说冲击还是比较大的。WWDC2019 中,苹果同时推出了 swiftUI,正式统一了 Apple 全平台 UI 开发解决方案,未来属于 swift,可见好大夫 iOS 客户端接入 swift 刻不容缓。

基础框架设计

iOS 客户端整体采用组件化的架构,使用 cocoapods 导入各个组件,业务之间通过中间件进行通信,基础组件包括网路库、图片库、支付库等。在接入 swift 之后,虽然基础私有库可以通过修改 podspec 文件进行 swift 私有库调用,但是为了统一和壮大 iOS 客户端的 swift 生态系统,对于部分私有库进行了 swift 化重构,生成一套专供 swift 调用的基础库,当然不是所有的私有库都进行了重构,而是根据具体的业务需求以及公司未来发展综合考虑,对一些工程中经常用到的宏定义,遍历构造函数以及视图约束框架等进行了 swift 化。


对于 UI 常用控件,网络库,图片库,支付库等,如果进行重构,则会出现影响范围较大,测试耗时很长,影响项目迭代,拿 UI 控件库来说只是进行了 podspec 文件修改,使其支持了 swift 私有库的调用,同时如果有新增的基础控件,首选 swift 语言来编写,减少 Objective-C 代码的使用。


经过一年时间的沉淀,iOS 客户端目前全量 swift 业务有直播业务、留言板业务,其他的业务的主流业务也已经使用了 swift 和 OC 混编的方式进行开发。


推进工程 swift 化遇到的问题

传统 Objective-C 项目接入 swift 一些问题始终是绕不过去的,如:


  • 主工程或者模块化中 swift 和 Objective-C 的混编怎么实现

  • Module 系统

  • swift 代码的规范性怎么解决

一、swift 和 OC 混编

针对上面的第一个问题,我们分为两种情况,第一种情况为 App Target 内部 swift 和 OC 混编,对于好大夫的医患两端来说之前一直使用 Objective-C 编写,所以在创建第一个 swift 文件时,会提示生成一个 bridging header 文件,点击 create 即可。



在 swift 文件中如果需要引入某个 OC 类,将需要使用的 OC 类在 bridging 文件进行 #import 即可。在 OC 类中如果需要引入 swift 文件,只需要在 OC 类中引入 import “ProductModuleName-Swift.h”,其中 ProductModuleName 表示当前 Target 的名称。ProductModuleName-Swift.h 文件为编译产物,可以看到该文件将 swift 文件中的代码生成为对应 OC 中的 interface 和 implementation。


第二种情况为模块内部进行 swift 和 OC 混编,或者 OC 私有库需要提供给外部的 swift 文件或者 swift 私有库使用,针对这种情况我们可以统一配置,好大夫客户端采用的 cocoapods 方式引入组件,所以通过对组件 podspec 进行配置,添加 s.pod_target_xcconfig = {‘DEFINES_MODULE’ => ‘YES’} 将组件模块进行 module 化,可以使用 cocoapods 自动生成的 umbrella.h 文件或者自己新建一个 umbrella header 将需要暴露给 swift 调用的 ObjC 头文件在这个 umbrella header 中导入,在需要调用的 swift 文件中直接 import Module 即可。

二、Module 系统

2.1 LLVM Module 系统

既然说到了 OC 和 swift 混编,那么不得不提苹果在 2012 年 11 月提出 LLVM 的 Module 系统,简单讲就是用树形的结构化描述来取代以往 #include,例如传统的 #include <stdio.h>变成了 import std.io,逼格更高,这样做的好处主要有:


  • 语义上完整描述了一个框架的作用;

  • 提高编译时的可扩展性,同一模块只需要编译或导入一次,避免了头文件的多次引用、解析;

  • 减少碎片化,每个模块只处理一次,环境的变化不会导致不一致;

  • 对工具友好,工具(语言编译器)可以获取更多关于 module 的信息,比如链接库,比如语言是 C++ 还是 C;

2.2 modulemap 文件

modulemap 文件就是对一个框架,一个库所有文件的结构化描述,默认文件名是 module.modulemap。如下图,可以看到使用 umbrellar header 关键字导入 HDFIMComponent-umbrella.h 中所有的.h 文件。



umbrellar header 关键字的意思为 Master Header File,可以使用


#import <UIKit/UIKit.h>
复制代码


替代


#import <UIKit/UIViewController.h>#import <UIKit/UILabel.h>#import <UIKit/UIButton.h>#import <UIKit/UIDatePicker.h>
复制代码

2.3 Swift Module

项目中的每一个 Target(无论是 framework 还是 app),就叫做一个 Swift Module。这是 Swift 分发代码的方式,我们可以通过 import 命令,来使用定义在其他 Module 中的代码,而每个 Module 意味着:


  • 一个和 Module 同名的命名空间

  • 一个独立的访问控制范围


对第一条来说,这也就是为什么在一个项目中,定义在不同 Swift 文件中的类可以在不同的文件中直接使用而不需要 include 的原因,因为它们本身就在同一个 namespace 里。


对于第二条来说,当我们通过 import 在项目中引入一个 module 时,就相当于打开了这个 module 对应的命名空间,就可以使用这个 module 中所有标记为 public 或者 open 的代码。


三、规范 swift 代码

不同的人有不同的编码习惯,导致了工程中代码风格的多样性,为了提供 swift 代码的可读性以及统一性,iOS 客户端引入了 swiftlint,swiftlint 是 Realm 开源的一个加强检查 swift 语言规范的库,可以满足强迫症的所有幻想,通过对 swift 代码进行扫描,统一编码风格,从每一个文件到每一个函数,甚至每一个变量都进行规范,将 swiftlint 扫描后的结果接入到 SonarQube,使用网页进行展示,方便分类修改,将具体的代码分配给对应的负责人,严格按照要求进行修改,保证客户端 swift 代码坏味道为 0。


未来规划

swift 是一门优秀的编程语言,就目前苹果主推 swift 语言以及编程语言排行榜上 swift 已经从 18 位上升到 12 位,可见未来国内 swift 语言也将会盛行。接入 swift 简单,但是如果想要完美的兼容当前工程并非一件容易的事,只有选择正确的方式,合适的解决方案才能将 swift 与原工程成功融合在一起。



好大夫 iOS 客户端目前已经全量使用 swift 进行开发,计划每年做新系统适配时会升级 swift 版本,紧跟时代的发展。后续接入 swift package manager 替代 cocoapods、声明式 UI 替代现有命令式 UI。


作者介绍:


陶庆玮:好大夫 iOS 开发工程师,主要负责组件化工程、基础库开发和客户端稳定性相关工作,以及 Swift 语言落地。


2020-09-23 08:005254

评论

发布
暂无评论
发现更多内容

「1.4万字」玩转前端 Video 播放器 | 多图预警

阿宝哥

大前端 流媒体 Video播放器 HLS

架构师训练营第六周作业

sunnywhy

学会使用Vue JSX,一车老干妈都是你的

前端有的玩

Java Vue 大前端 技巧 React

一个成都程序猿写于离开北京一周年与26岁生日的这一天

why技术

生活 程序人生 北漂 成都

总结

Kiroro

架构师训练营第六周作业

王铭铭

CAP 原理

Z冰红茶

最右JS2Flutter框架——渲染机制(二)

刘剑

flutter 大前端 跨平台 探索与实践

NOSQL - 第六周总结

孙志平

蟒周刊-429-Python 3.8.4 可用ed

ZoomQuiet大妈

Python 大妈 蟒周刊

NOSQL - 第六周作业

孙志平

架构师训练营」第 6 周作业

edd

极客大学架构师训练营

程序员的眼界真的不要,也不能只局限于技术

非著名程序员

极客时间 程序员 提升认知

架构师训练营第6周作业

饶军

CAP

Kiroro

架构师训练营第六周

大丁💸💵💴💶🚀🐟

week6 学习总结 Nosql

Z冰红茶

MySQL 高可用和分布式数据库(训练营第六课)

看山是山

zookeeper CAP 主从复制 主主复制 MySQL 高可用

架构师训练营第六周总结

sunnywhy

猿灯塔:spring Boot Starter开发及源码刨析(六)

猿灯塔

图解:有向环、拓扑排序与Kosaraju算法

淡蓝色

Java 数据结构 算法

Apache Flink 是什么?

Apache Flink

flink

GaussDB for DWS:内存自适应控制技术总结

华为云开发者联盟

大数据 数据湖 内存管理 sql 华为云

Doris 临时失效 UML 时序图(训练营第六周)

看山是山

Doris

学习总结 - 第 6 周

饶军

我学会了用Python预测股票价格

博文视点Broadview

Python 读书笔记 算法 数据分析

探秘 Spring 的 PropertyEditor

CoderLi

Java spring 后台

static关键字真能提高Bean的优先级吗?答:真能

YourBatman

spring springboot SpringCloud 极客大学架构师训练营 Spring Bean

CAP 原理及Doris 临时失效的处理过程

Acker飏

极客大学架构师训练营 CAP

CAP原则

熊威

Doris临时失效处理过程的UML时序图

周冬辉

Swift在好大夫APP医患两端的打怪升级_AI&大模型_好大夫在线技术团队_InfoQ精选文章