# 老司机 iOS 周报 #79 | 2019-08-12

![ios-weekly](https://github.com/SwiftOldDriver/iOS-Weekly/blob/master/assets/ios-weekly.png?raw=true)
老司机 iOS 周报，只为你呈现有价值的信息。

你也可以为这个项目出一份力，如果发现有价值的信息、文章、工具等可以到 [Issues](https://github.com/SwiftOldDriver/iOS-Weekly/issues) 里提给我们，我们会尽快处理。记得写上推荐的理由哦。有建议和意见也欢迎到 [Issues](https://github.com/SwiftOldDriver/iOS-Weekly/issues) 提出。

## 文章

### 🌟 🐢 [抖音研发实践：基于二进制文件重排的解决方案 App 启动速度提升超 15%](https://mp.weixin.qq.com/s/Drmmx5JtjG3UtTFksL6Q8Q)

[含笑饮砒霜](https://weibo.com/chinafishnews/)：App 的启动速度通常是 App 给用户的第一印象，重要性不言而喻。除了传统的通过修改业务代码的方式，抖音 iOS 客户端团队，开拓性的发现通过修改代码在二进制文件的布局可以提高启动性能。

本文从原理出发，介绍了抖音 iOS 客户端团队是如何通过静态扫描和运行时 trace 找到启动时调用的函数，然后修改编译参数完成二进制文件的重新排布。相信在未来，二进制文件重排也会有更多应用场景。

>  最近 Facebook 也在一个技术大会上分享了类似的内容，强烈推荐: [视频](https://www.facebook.com/atscaleevents/videos/664302790740440/)

### 🌟 🐎 [swift-corelibs-foundation Release Notes for Swift 5.x](https://github.com/apple/swift-corelibs-foundation/blob/master/Docs/ReleaseNotes_Swift5.md)

[@享耳先森](https://github.com/iblacksun)，[@老驴](https://github.com/olddonkey)：

Swift 开源版的 Foundation 在 Swift 5.x 有了不小的改动：

1. 依赖：

    Swift 开源版的 Foundation 初版实现大量地使用了开源库，这次在新版本中整理了一下开源库的依赖，并且把之前的 Foundation 拆分成了三个库：
    
    * Foundation
    * FoundationXML：考虑到大部分人不会使用 XML 相关的功能，所以通过 FoundationXML 将 libxml2 的依赖从 Foundation 里拆了出来。
    * FoundationNetwork：将 URLSession 相关的网络请求 API 拆了出来。
    
    FoundationNetwork 的情况比较复杂一点，之前论坛里的草案 Pitch: Move URLSession to new FoundationNetworking module 比较详尽地介绍这一次的改动。
    
    Foundation 网络库使用的 [libcurl](https://forums.swift.org/t/pitch-move-urlsession-to-new-foundationnetworking-module/14002) 带来了太多子依赖，一部分甚至和 SwiftNIO 的依赖产生了冲突，并且开发组希望使用 SwiftNIO 作为 URLSession 的底层实现，这一次改动之后依赖链就变成了 FoundationNetwork -> SwiftNIO -> Foundation。

2. Objective-C Runtime 仿真：

    Foundation 为 Swift for Linux 提供了模拟仿真部分 Objective-C 方法。现在，Swift 5.1 中也可以用这样的方法了：
    
    ``` swift
    let someClass = NSClassFromString("NSTask")
    assert(someClass == Process.self)
    let someName = NSStringFromClass(someClass)
    assert(someName == "NSTask")
    ```

3. NSCoder 的改进：

    这个版本的 Swift Foundation 中改进了 `NSCoder` 的具体实现，让它能更接近 Darwin 中对应的部分。

4. NSSortDescriptor 的改动：

    现在，在 Swift Foundation 中包含了 `NSSortDescriptor` 的实现，同时它与 Objective-C 中对应部分兼容。因为有部分的 API 改动，所以推荐有用到 `NSSortDescriptor` 的开发者看一下对应的文档。

5. 其他改动：
    Scanner API 改进，现在不再需要做 Casting 了，更加符合 Swift 的语法习惯。FileHandle API 改进，主要是针对 NSError 变化上的变动，能够抛出 Error 而非直接 Crash 了。

### 🐢 [7000 个未解决 issue，Flutter 看起来很好，用起来挺疼](https://mp.weixin.qq.com/s/EAgzYQX5-4pu7HWaGwK7Ag)

[@CrazyCoderShi](https://github.com/CrazyCoderShi)：Flutter 自发布以后，国内外都掀起了 Flutter 的学习热潮，其中褒贬不一，本文作者分享了一些自己在学习过程中的一些心得和体会(吐槽😂)，好了先开始吐槽：

- 安装过程很漫长
- 一团糟的 Material Design
- 其他烦心事 (这里面包括了一些组建的 Bug)

目前 Flutter 在 GitHub 上有超过 7000 个 issues 未解决，这个数字真的很吓人。小编本人之前也用 Flutter 开发过 App ，我也趁着这波吐槽一下😂，因为问题远不止 Bernardo Ferrari 说的那些：

- 跟现有项目混和开发体验极差
- PlatformView 的表现相当差强人意，特别是在 iOS 上
- 生态发展欠缺的还是比较多的

略微做个总结，整体来看问题真的很多，但是 Flutter 自发布 1.0.0 以来还不到一年，发展速度已经是很快了，有不足之处，但也有不少惊艳之光，不然国内的大厂也不会纷纷都在布局 Flutter 技术的落地，其中走在最前面的咸鱼，想必大家都是知道的。所以，小编觉得，不管从哪个角度来看，都是一个值得尝试和学习的技术栈，毕竟技多不压身不是？

> 补充下原文链接：[Flutter looks good, but is painful. Here are my frustrations with it.](https://medium.com/@bernaferrari/from-android-dev-flutter-looks-good-but-is-painful-here-are-my-frustrations-with-it-81b4bbe739f8)。

### 🐎 [SwiftPreview](https://forums.swift.org/t/pitch-standard-library-preview-package/27202)

核心开发组发了一份草案，内容是新增一个开源库 SwiftPreview ，用来预发布一些 non-breaking 的 API 改动。

以往所有提案都必须赶上半年一趟车的 release 才能发布出来，但这对于相当一部分提案都是非必要的，如果发布后需要调整或者修改那就又是半年，例如 [SE-199 Bool 引入 Toggle 方法](https://github.com/apple/swift-evolution/blob/master/proposals/0199-bool-toggle.md)，在审核通过之后六个月才在 Swift 5 发布了出来。

所以这一次提案是想要加快 Swift 的 API 迭代速度，对于一些不需要编译器支持，非破坏性的功能都会考虑提前在 SwiftPreview 里发布以供大家提前使用，尽早提供反馈。

### 🐎 [SE-0261 Identifiable Protocol](https://github.com/apple/swift-evolution/blob/master/proposals/0261-identifiable.md)

[@Damonwong](https://github.com/Damonvvong)：在 SwiftUI 中引入了 Diff 的概念。意思就是在一个列表刷新的时候，会根据一个唯一标识符来判断是否需要重新渲染，如果通过 Diff 算法算得某个唯一标识符并没有变化，那么这块区域就不会重新渲染。而在这个事情中最重要的就是「唯一标识符」这个东西了，在 SwiftUI 中通过 Identifiable 来约束类型满足唯一标识符这个概念。当然，唯一标识符不仅仅可以使用在 Diff 算法中，还可以用在很多其他的地方，比如通讯录联系人的唯一标识符。因此在[Swift 社区讨论](https://forums.swift.org/t/move-swiftuis-identifiable-protocol-and-related-types-into-the-standard-library/25713)之后，决定把 Identifiable 这个协议加入到标准库中，并在 Swift 5.1 发布。
    
### 🐎 [CocoaPods 1.8 Beta is Here!](http://blog.cocoapods.org/CocoaPods-1.8.0-beta/)

[@红纸](https://github.com/nianran)：Cocoapods 1.8.0 Beta 版来了！本次更新为我们带来了如下内容：

1. Master Specs Repo 默认改为 CDN，有效的加快初始设置和依赖分析速度
2. info_plist Podspec DSL：在使用 use_frameworks! 的动态框架中，pod 现在可以自动生成 Info.plist 文件，并且你可以在 podspec 中使用键值对来修改 plist 文件中内容
3. project_name Podfile DSL：在 1.7 版本，pod 可以生成多 Project 的 Pod 功能，在 1.8 中对其进行了扩展，自定义多个 pod 可合并成一个 Project
4. UI Test Bundle Support：支持 UI 测试项目的生成，你可以在 podspec 中选择 :unit/:ui 来配置，其测试的工程可以通过 app_host_name 来进行设置

## 工具

### 🌟 [Auto Layout: WTF to FTW](https://www.rightpoint.com/rplabs/2019/06/wtf-auto-layout-for-ios-in-swift/)

[@looping](https://github.com/looping)：[WTF Auto Layout?](https://www.wtfautolayout.com/) 是一个可以用来辅助调试 Auto Layout 问题的网站，它能够对我们调试应用时出现的约束歧义信息进行解析并可视化显示。但是我们都知道在调试的时候出现 Auto Layout 约束歧义是不影响应用正常运行的，这样当打印的日志偏多的时候，就很难及时发现这类提示。即使发现了，还要手动复制提示文本到网站的输入框里，比较麻烦。所以本文就介绍了通过在 Xcode 里设置 Symbolic Breakpoint，当调试应用时有触发 `UIViewAlertForUnsatisfiableConstraints` 就执行自定义的 Python 脚本，自动获取和解析断点调试的入参信息并打开 [WTF Auto Layout?](https://www.wtfautolayout.com/) 这个网站。想时刻监控 Auto Layout 问题的同学可以尝试体验下这个工具流程，当然也可以优化下并不是每次都打开网站，而是先记录到文本，再找个时间进行集中分析处理。同时文章也涉及了一些调试技巧，可以学习下。

### [Swift API-Digester](https://github.com/apple/swift-nio/commit/07e7e01c76be20640ddc3770d7b16e87eedf20de)

[@享耳先森](https://github.com/iblacksun)：Swift 5.1 里新增了一个 `api-digester` 功能，用来打印和比较编译产物的 API，Swift-NIO 在此基础上搭建了一个 API Diff 功能，可以预见未来开源框架都会使用这个功能来生成 API Diff，帮助检验 Pull Request 对于 API 的影响，ChangeLog 的生成等等。

用类似这样的命令：`swift api-digester -diagnose-sdk --input-paths "dir1" -input-paths "dir2"` 就能比较两个编译产物的 API 区别，生成类似下面的结果：

> Removed Decls
> Constructor WebSocketFrameDecoder.init(maxFrameSize:automaticErrorHandling:) has been removed
> EnumElement WebSocketOpcode.unknownControl has been removed
> EnumElement WebSocketOpcode.unknownNonControl has been removed

> Renamed Decls
> Func WebSocketFrameDecoder.decode(ctx:buffer:) has been renamed to Func WebSocketFrameDecoder.decode(context:buffer:)
> Func WebSocketFrameDecoder.decodeLast(ctx:buffer:) has been renamed to Func WebSocketFrameDecoder.decodeLast(context:buffer:seenEOF:)
> Func WebSocketFrameEncoder.write(ctx:data:promise:) has been renamed to Func WebSocketFrameEncoder.write(context:data:promise:)
> Func WebSocketProtocolErrorHandler.errorCaught(ctx:error:) has been renamed to Func WebSocketProtocolErrorHandler.errorCaught(context:error:)

> Type Changes
> Constructor UInt8.init(webSocketOpcode:) has return type change from UInt8? to UInt8

### [Matrix-iOS 耗电监控](https://mp.weixin.qq.com/s/HS4DJDpCS6uppQ9WmVR_Tg)

[JimQ](https://github.com/waz0820)：Matrix 是一款微信团队研发并日常使用的性能探针工具，4 月份开源，当时的监控范围包括崩溃、卡顿和爆内存，现在新增了耗电监控功能。
实现原理是，在应用启动后开启一个检测子线程，检测线程不断去识别出当前应用哪个线程的 CPU 占用过高（通过 `thread_basic_info` 获得），将耗 CPU 多的线程的堆栈（使用 `backtrace()` 函数获取）收集起来。当应用 CPU 占用达到阈值时，耗电监控将收集到的堆栈组合（接合成调用树，并标记每个函数被收集的次数）形成耗电堆栈（函数次数越大，所占用 CPU 越多）。

## 代码

### 🌟 [Swift-MemoryLayout](https://github.com/TannerJin/Swift-MemoryLayout)

[@四娘](https://kemchenj.github.io)：作者在学习 Swift 内存布局的过程中，写了一个简单的 Demo 演示如何使用指针去读取 Array / Dictionary 内部的变量，进一步验证各种类型的内存布局。

这个项目很好地演示了 Swift 里的指针操作，非常值得一看！！！

### 🐕 [CombineCocoa](https://github.com/freak4pc/CombineCocoa)

[@老峰](https://github.com/GesanTung)：CombineCocoa 是基于 [Combine](https://developer.apple.com/videos/play/wwdc2019/722/) 对  UIKit Controls 的封装，类似 RXcocoa 实现了许多组件的绑定功能，可以直接把值和控件互相绑定，避免通知、监听、delegate 等，极大的简化了 UI 相关逻辑处理，示例如下：

- textField.textPublisher
- segmented.selectedSegmentIndexPublisher
- slider.valuePublisher
- button.tapPublisher
- swtch.isOnPublisher
- datePicker.datePublisher
- ...

### [CombineRxSwiftPerformance](https://github.com/quickbirdstudios/CombineRxSwiftPerformance)

[@邦Ben](https://weibo.com/linwenbang)：这个 Repo 对比了 Combine 和 RxSwift 目前常用方法的性能表现，作为选型资料可以看下。

最后结论，Combine 速度更快，平均性能比 RxSwift 高出41%。

![测试结论](https://user-gold-cdn.xitu.io/2019/8/12/16c83b285f096ee2?w=3469&h=1570&f=png&s=308546)

## 内推

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

如果你想**找工作**，点这里：https://www.yuque.com/iosalliance/article/bhutav

如果你想**招人**，点这里：https://www.yuque.com/iosalliance/article/ycyhf3

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

## 关注我们

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

![](https://github.com/SwiftOldDriver/iOS-Weekly/blob/master/assets/qrcode_for_wechat.jpg?raw=true)

同时也支持了 RSS 订阅：https://github.com/SwiftOldDriver/iOS-Weekly/releases.atom 。

## 说明

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

预计阅读时间：🐎 很快就能读完（1 - 10 mins）；🐕 中等 （10 - 20 mins）；🐢 慢（20+ mins）


