老司机 iOS 周报 #80 | 2019-08-19

4,731 阅读10分钟

老司机 iOS 周报,只为你呈现有价值的信息。

你也可以为这个项目出一份力,如果发现有价值的信息、文章、工具等可以到 Issues 里提给我们,我们会尽快处理。记得写上推荐的理由哦。有建议和意见也欢迎到 Issues 提出。

新手推荐

🐕 深入理解 iOS 事件机制

@老峰:文章通过实例详细介绍 iOS 事件机制,主要包括以下内容:

  • 事件的生命周期:系统响应阶段、APP 响应阶段
  • 探测链与响应链:Hit-Testing、Responder Chain
  • 手势识别器与原生触摸事件:UIGestureRecognizer Methods、UIEvent 与 UIGestureEnvironment、UIGestureRecognizer Properties

文章

🌟 🐕 Combine vs. RxSwift: Should you switch to Combine?

@莲叔:Apple 官宣了 Combine,让 Reactive 社区感觉异常振奋,各种分析文章层出不穷。Combine 的推出势必会加速响应式编程的流行,会的程序员越多那我们在工作中实际使用的机会也就越多。但另一方面,很多同学心中也会有这样一个问题,Combine 会取代 RxSwift 的吗?我该学哪个?

这篇文章解释了这个疑问,文章首先简单介绍了 Combine,并且命名规范,错误类型和异常处理、性能、兼容性、UI 兼容性等多个方面较全面的比较了两个框架,两者有非常多相似的地方,但 RxSwift 毕竟已经发展了几年,细节更完善。而且最要命的就是 Combine 并不支持对老的 iOS。简单的说,你现在应该开始学 Combine,不过如果要选型生产环境的话,还是优先考虑 RxSwift.

🌟 🐎 由「抖音二进制文件重排」想到的

@zvving: 上周热文 抖音研发实践:基于二进制文件重排的解决方案 APP启动速度提升超15% 发布后,作者有感而发,写出此文:

好的文章常能引发好的讨论。建议感兴趣的同学可以根据文章的指引,尝试落地 PGO 方案,为社区带来更好的优化启动实践。

🌟 🐎 RxSwift 兼容 Combine 的讨论

@没故事的卓同学:SwiftUI 框架设计的时候 data flow 就是以 Combine 作为实践方案。因此如果用 SwiftUI 不用 Combine 你得到的是一个没有灵魂的 SwiftUI。但是当前 Combine 离工业水准还有不少距离,可行的方案可能是外围的数据还是用 RxSwift 处理,要使用的时候把 Observal 桥接成 Publisher。 RxSwift 社区也意识到如果 apple 生态里最后只有一个响应式框架,必然是亲儿子 Combine。当前 Combine 的先天劣势是从 iOS 13 开始,RxSwift 则是从 8.0 开始兼容。RxSwift 社区也会顺应潮流,在未来某个成熟时刻 RxSwift 内部实现会改成使用 Combine。如果这一步做的好,未来从 RxSwift 转到 Combine 会比较顺滑。

🐎 谁是 App 版本帝

@红纸:每个应用的发版周期都是不同的,本文提供了获取任意 APP 发版间隔/紧急发布次数的解决方案。并提供了排序脚本,美化爬虫数据,结论更加直观。从数据结论上看,过去 6 个月很多热门 APP 都是保持在 7/8 天的发版周期。

🐎 The (not so) hidden cost of sharing code between iOS and Android

@老驴:这是一篇前两天在微博上引起热议的文章。文章是 DropBox 的工程团队写的,主要讲述了在他们的实际开发过程中,他们所遇到的跨平台方案中的问题及他们的考量。文章不长,但是其中有几个点还是挺有意思的。

文章中提到了一个之前鲜有提到的问题:开发团队的接受程度。这里指的是自己的团队对跨平台开发有没有兴趣,能不能让大家能做自己愿意做的事情。简单来说,就是以人为本的思想。这一点在国内的互联网环境下应该相对来说是比较少见到的,而国外的互联网企业对这方面有一定的重视。所以在技术选型上,国外公司考虑的东西可能会更多一点。

周报之前也有类似的文章,可以通过这里进行查阅。

🐕 🚧 Create, Push, and Present Any View Controller in 1 LOC using Metaprogramming

@xiaofei86:使用 Storyboard 设计界面非常方便,但当我们想要使用代码实例化 Controller 并做跳转,甚至实现动态跳转,就会变得十分麻烦。我们需要编写大量的样板代码来实例化 Controller 并设置参数。本文提出了使用元编程的理念解决此问题的思路。通过 Sourcery 自动生成创建代码,通过 Extension 简化调用并隔离命名空间,最终将创建过程简化为 1 行。

🐕 iOS LLDB 中基于内存单指令 patch 实现反反调试

@J_Knight_:本文作者介绍了一种基于内存单指令 patch 的方式进行反反调试的方案,方案的大致流程如下:

  1. 使用 mmap 新建一块内存,把这块内存叫做 new
  2. 使用 vm_copy 把想要篡改的处于 __text 段内的内存(把这块内存叫 target )拷贝到 new 里
  3. 向 new 里写入想执行的代码
  4. 调用 mprotect 把 new 改为 rx 。因为 mmap 出来的内存的 max_protection 是 rwx ,所以这里 mprotect 改权限没问题
  5. 调用 mach_vm_remap 把 new 的内容反映回 target 里

在文章结尾,作者举了实际例子来验证了这个反反调试的方法。

🐎 技术人如何通过了解业务,获取晋升机会?

@水水:本文作者伐薪是阿里巴巴高级技术专家,14年初入阿里时,没有过多地思考业务痛点和了解业务策略。后来,经历过晋升,当晋升评委,主动学习业务,最后,完成了从技术专家向综合性 TL 转变。作者总结了不少经验,分享给你们,希望能给读者带来少许启发。

  • 业务先赢是技术第一要务
  • 如何理解业务
  • 在业务理解上的收获

🐕 Phantom types in Swift

@四娘:这周 Swift by Sundell 为我们介绍的是一种叫做 Phantom Types 的技巧,在 Swift 里处理一些有限集合的时候,我们通常会将它声明为 enum,但经常会有一些特殊情况需要照顾:

func openEditor(for document: Document) {
    switch document.format {
    case .text: openTextEditor(for: document)
    case .html: openHTMLEditor(for: document)
    case .pdf:  assertionFailure("Cannot edit PDF documents")
    }
}

这样的代码无法通过类型系统去限制错误的调用,作者尝试从 Swift 的标准库里寻找解决方案,发现标准库里 UnicodeUTF8 等格式作为一个类型声明出来,而不是直接使用 enum case,使用这种思路我们就可以把代码改造成这样:

enum DocumentFormat {
    enum Text {}
    enum HTML {}
    enum PDF {}
}

func openTextEditor(for document: Document<DocumentFormat.Text>) { ... }
func openHTMLEditor(for document: Document<DocumentFormat.HTML>) { ... }

🐕 美团 iOS 工程 zsource 命令背后的那些事儿

目前,许多团队都会使用 CocoaPods 进行三方库的管理,而对于一些进行了组件化的团队,也会使用 CocoaPods 进行私有组件库的管理工作。在组件化过程中,往往为了提高工程的构建速度,会对组件进行二进制化。这也带来一个问题,就是调试的时候,不能提供清晰的调试信息。基于这个问题,美团团队为 CocoaPods 开发了一个插件 zsource,可以在调试过程中迅速调出源码进行调试,很好地解决了这一痛点。文章介绍了 zsource 命令的开发始末,而整个开发过程总结为几个阶段:

  • 原理猜想
  • 查阅资料
  • 简单粗暴的尝试
  • 柳暗花明
  • 工程化

美团的这次开发经验也说明,有时候,为了解决一些问题,我们也可以不拘泥于常规的开发方式,可以大胆的进行猜想并逐步去验证结论,通过类似逆向的方式,得到想要的答案。

工具

🌟 Catching Unsatisfiable Auto Layout Constraints in UITests on CircleCI

@loopingInstabug 是应用内问题反馈和 BUG 搜集服务提供商,他们为了不想让使用他们产品的开发者在调试的时候看到来自该工具的 Auto Layout 约束冲突,所以想尽早发现并解决这类问题。

捕获 Auto Layout 约束冲突常规思路是通过添加 UIViewAlertForUnsatisfiableConstraints 的调试断点,这个在我们往期的 #79 - Auto Layout: WTF to FTW#70 - XCTAssertAutolayout 中都有相关介绍。

而本文提供了另外一个使用场景,就是在持续集成跑 UI 自动化测试时也添加相关检测,大致思路如下:

  • 开启 LLDB,在终端输入 lldb,最终会使用 lldb --source lldb.cmd
  • 附加 LLDB 进程到要调试的应用,process attach --name "InstabugDemo" --waitfor
  • 设置断点,b UIViewAlertForUnsatisfiableConstraints
  • 添加调试命令,文本采用的方案是使用 Python 把错误信息以文件的形式写到桌面,待测试出错后查看,breakpoint command add -s python
  • 继续运行,continue

由于持续集成要保证流程的自动化,所以得循环执行上面的逻辑,这样就还需要下面两个步骤:

  • 杀掉调试进程,process kill
  • 重新执行流程,command source lldb.cmd

具体细节可以阅读原文深入了解,但在进行实践的时候,由于集成环境各异,要根据实际场景进行探索调整。

代码

YBTaskScheduler

iOS 任务调度器,为 CPU 和内存减负。源码结构简洁,模式清晰,值得一读。

  • 特性:
    • 将任务用容器管理起来延迟执行,实现任务执行频率控制、任务总量控制。
    • 利用 C++ 栈、队列、优先队列实现三种调度策略,性能优越。
  • 应用场景:
    • 主线程任务量过大导致掉帧(利用组件为任务调度降频)。
    • 短时间内执行的任务量过大,而某些任务失去了执行的意义(利用组件的任务淘汰策略)。
    • 需要将任务按自定义的优先级调度(利用组件的优先队列策略)。

本工具由 波儿菜 自荐。

音视频

Performance @Scale 2019 recap

@张嘉夫:在今年的 Scale 活动中,来自 Facebook、Google、NVIDIA 和其他公司的演讲者分享如何用创新的方式来设计大规模系统。开发能够部署到数百万或数十亿人的应用和服务会带来独特的、复杂的性能挑战,优化基础架构、扩展 Web 服务以及开发快速移动应用都能够保证大规模系统的性能。

🐢 Flutter 的性能测试和理论

@CrazyCoderShi:本视频为 Google Flutter 团队的软件工程师 Xiao Yu 在 2018 谷歌开发者大会做的演讲,演讲题目是《Flutter 的性能测试和理论》, 这个视频里将会通过近半个小时的视频和演示带大家了解 Flutter 应用渲染时的时间消耗,了解这些之后会更好的帮助开发者们发现应用的性能问题,同时介绍了性能测试工具的使用和问题排查方法,非常值得收藏和分享

内推

老司机周报团队联合知识小集和 SwiftGG 翻译组收录了一份靠谱的内推职位。

如果你想找工作,点这里:www.yuque.com/iosalliance…

如果你想招人,点这里:www.yuque.com/iosalliance…

当然,也欢迎你关注我们每一期的周报,我们会在每期周报底部及时更新编辑内推岗位。

关注我们

我们开通了公众号,每期发布时公众号(OldDriverWeekly)会推送消息,欢迎关注。

同时也支持了 RSS 订阅:github.com/SwiftOldDri…

说明

🚧 表示需翻墙,🌟 表示编辑推荐

预计阅读时间:🐎 很快就能读完(1 - 10 mins);🐕 中等 (10 - 20 mins);🐢 慢(20+ mins)