写点什么

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:004675

评论

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

快速搭建Jenkins集群

程序员欣宸

DevOps jenkins 11月月更

从这两道题重新理解,JS的this、作用域、闭包、对象

loveX001

JavaScript

一个好的安全团队应该具有怎样的素质

穿过生命散发芬芳

11月月更 安全团队

张益唐111页论文攻克朗道-西格尔零点猜想

老周聊架构

数学 11月月更 朗道-西格尔零点猜想

云原生系列三:K8s应用安全加固技术

叶秋学长

#k8s K8s 多集群管理 安全加固 11月月更

湖仓一体电商项目(四):项目数据种类与采集

Lansonli

湖仓一体 11月月更

拿到大厂前端offer的前端开发是怎么回答面试题的

loveX001

JavaScript

JavaScript-防抖

格斗家不爱在外太空沉思

JavaScript 前端 11月月更

黑客“劫持”了一颗卫星,用它直播黑客大会和放电影

博文视点Broadview

索引的基础知识

阿泽🧸

索引 11月月更

2022-11-08:以下go语言代码输出什么?A:2;B:编译错误;C:运行 panic。 package main import “fmt“ func main() { a := []int

福大大架构师每日一题

golang 福大大 选择题

【docker】软链接迁移docker碰到的问题

非晓为骁

Docker 迁移

跟着卷卷龙一起学Camera--低延迟02

卷卷龙

ISP camera 11月月更

令人头秃的js隐式转换面试题,你能做对吗

loveX001

JavaScript

随机森林-随机森林在乳腺癌数据上的调参

烧灯续昼2002

Python 机器学习 算法 sklearn 11月月更

你是如何使用React高阶组件的?

beifeng1996

React

CSS学习笔记(三)

lxmoe

CSS 前端 学习笔记 11月月更

阿里云日志服务SLS携手观测云发布可观测性解决方案,共建可观测应用创新

TalkingData

阿里云 可观测 存储上云 日志服务 sls

算法题学习---合并两个排序的链表

桑榆

算法题 11月月更

湖仓一体电商项目(五):内网穿透工具-网云穿

Lansonli

湖仓一体 11月月更

手写一个Redux,深入理解其原理-面试进阶

beifeng1996

React

如何在 Rocky Linux 上安装 MinIO 存储?

wljslmz

对象存储 S3 Minio Rocky Linux

JavaScript-节流

格斗家不爱在外太空沉思

JavaScript 前端 11月月更

4.NLP领域任务如何选择合适预训练模型以及选择合适的方案【规范建议】【ERNIE模型首选】

汀丶人工智能

nlp 11月月更

京东前端经典react面试题合集

beifeng1996

React

【奖项征集】参与第四届中国“数据质量管理”奖项评选,DQMIS 2022门票免费领!

数据质量管理智库

数据 数据治理 数据安全 数据隐私计算 数据要素

Hessian Hessian2 JDK 序列化性能对比

water

从“青铜”到“王者”,制造企业的数字化闯关记

脑极体

互联网+背景下企业客户服务的创新之路

Baklib

制胜出海赛道 华为应用海外联运助力开发者获量增长

叶落便知秋

华为开发者大会2022

腾讯前端二面常考react面试题总结

beifeng1996

React

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