【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

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 语言落地。


公众号推荐:

跳进 AI 的奇妙世界,一起探索未来工作的新风貌!想要深入了解 AI 如何成为产业创新的新引擎?好奇哪些城市正成为 AI 人才的新磁场?《中国生成式 AI 开发者洞察 2024》由 InfoQ 研究中心精心打造,为你深度解锁生成式 AI 领域的最新开发者动态。无论你是资深研发者,还是对生成式 AI 充满好奇的新手,这份报告都是你不可错过的知识宝典。欢迎大家扫码关注「AI前线」公众号,回复「开发者洞察」领取。

2020-09-23 08:004171

评论

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

react源码解析19.手写迷你版react

buchila11

React

TCP socket和web socket的区别

Jerry Wang

前端 node,js 1月月更

AWS Command Line Interface 使用S3入门

阿呆

AWS S3

读《底层逻辑》

wood

300天创作

使用亚马逊云科技安全服务防御、检测和响应 Log4j 漏洞

亚马逊云科技 (Amazon Web Services)

网络

大咖眼中的AI开源|王敏捷:深图在人工智能中的探索和研究

亚马逊云科技 (Amazon Web Services)

网络

架构师实战营3期毕业设计

小饭🍎

Amazon EC2 串行控制台——化繁为简,高效解决网络问题

亚马逊云科技 (Amazon Web Services)

网络

尚硅谷《MySQL高级特性篇》教程发布

@零度

MySQL

元宇宙,以区块链为核心的Web3.0数字生态

CECBC

为什么要把系统拆分成分布式的?为啥要用dubbo?

JavaEdge

1月月更

面试突击15:说一下HashMap底层实现?及元素添加流程?

王磊

Java 常用类大讲解!3️⃣(手写 API、源码必备)

XiaoLin_Java

Java 数组 1月月更

1月月更|推荐学Java——第一个MyBatis程序

逆锋起笔

Java mybatis SSM框架 MyBatis标签 mybatis配置

“5G+区块链”护航新生儿转诊“生命通道”

CECBC

react源码解析20.总结&第一章的面试题解答

buchila11

React

大咖眼中的AI开源 | 张建:图神经网络和DGL的实际应用

亚马逊云科技 (Amazon Web Services)

网络

一个基于PoS共识算法的区块链实例解析(升级版)

恒生LIGHT云社区

区块链 共识算法 PoS

如何提高后台服务应用问题的排查效率?日志 VS 远程调试

Jerry Wang

node.js 后台开发 1月月更

Magic UI四子围城,2022折叠屏灵魂觉醒

脑极体

站在面试官角度,看求职与内卷

程序人生

开源走向世界(下):从数据库技术演进看开源力量丨BDTC 2021

PingCAP

如何优雅的遍历Mycat分库表

编程江湖

mycat

模块六作业

Geek_e6f7f6

架构训练营

Kafka的生产集群部署

编程江湖

kafka

城墙上的“云镜派”,如何守护云上资产安全?

脑极体

用复杂的方式学会数组(Python实现动态数组)

宇宙之一粟

Python 数据结构 数组 1月月更

Hibernate 如何生成 JPA 的 Metamodel

HoneyMoose

IntelliJ IDEA 的 Metamodel 配置

HoneyMoose

ReactNative进阶(十四):初探 Gradle

No Silver Bullet

Gradle React Native 1月月更

JavaScript 12种设计模式汇总

编程江湖

JavaScript

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