Swift 于 2015 年正式开源。
一、目录简介
Github:https://github.com/apple/swift
几个可能会经常看的目录:
- docs:一些文档
- stdlib:Swift 源码
- lib:C++源码
- include:C++头文件
标准库源码位置:
https://github.com/apple/swift/tree/main/stdlib/public/core
二、Metadata 分析
文档:https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst
2.1. 结构布局
类的前 8 个字节存储的就是类相关的信息,指向Metadata
。那么Metadata
存储的是什么呢(官方文档也没细说,只能从 Swift 源码看下相关描述)?
Metadata
是区分类型的,不同类型的Metadata
是不同的(比如protocol、enum、class、struct、NSObject
等等是不同的Metadata
)。Metadata
存储哪些内容和 ABI 有关,在 Swift5.0 的时候 ABI 已经稳定下来了(官方对应版本描述为 Stable)。而 ABI 稳定意味着Metadata
结构已经稳定(比如 Swift2.0 的class
在Metadata
结构中的第 32 字节位置开始,可能在 Swift4.0 的时候变为第 48 字节位置开始存储,其他类型的存储位置也可能已经发生变化)。
虚表的
0x50
偏移量就是偏移其类型的Metadata
所占字节。
2.2. 作用
Metadata
的作用是什么呢?
在 OC 中如果要想知道一个类有哪些属性,可以通过runtime
的一些方法获取。但在纯 Swift 中,要想知道对应类型有哪些存储属性,只能通过Metadata
获取。
经典应用场景:字典转模型(JSON -> Model)。
但是由于每种类型的Metadata
结构布局不一样,所以需要对很多类型做布局解析。
三、反射
反射是编程语言中一项强大的能力,比如 Java 语言的反射机制。
- 对于任意一个类型,都能够动态获取这个类的所有属性和方法信息
- 对于任意个实例,都能够动态调用它的任意方法和属性
Swift 的反射机制目前还比较弱,通过Mirror
类型来提供简单的反射功能(只能获取到类型的属性名称,但是属性类型或泛型是获取不到的)。
示例代码:
struct Person {
var name: String?
var age: Int?
}
let mirror = Mirror(reflecting: Person(name: "daben", age: 20))
print(mirror.displayStyle as Any) // 输出:Optional(Swift.Mirror.DisplayStyle.struct)
print(mirror.subjectType) // 输出:Person
print(mirror.superclassMirror as Any) // 输出:Person
for case let (label?, value) in mirror.children {
print(label, value)
}
/*
输出:
name Optional("daben")
age Optional(20)
*/
四、常用第三方库
4.1. 网络请求
Github:https://github.com/Alamofire/Alamofire
4.2. 图片缓存
Github:https://github.com/onevcat/Kingfisher
Kingfisher 默认不支持 WebP 格式的图片,需要额外安装 KingfisherWebP
pod 导入:
pod 'KingfisherWebP'
使用方法:
imageView.setImage(with: URL(string: user.avatar),
options: [.processor(WebPProcessor.default),
.cacheSerializer(WebPSerializer.default)])
4.3. JSON 访问
Github:https://github.com/SwiftyJSON/SwiftyJSON
注意:该库仅仅是为了方便访问 JSON,而不是 JSON 转 Model
4.4. 字典转模型(JSON-Model)
Github:https://github.com/kakaopensource/KakaJSON
五、前缀
为防止和系统 API 或第三方库命名冲突,OC 中经常在类名、方法、属性前面加前缀(如 DBViewController)。
但是在 Swift 中不需要加前缀,也不建议加前缀。因为当函数名和第三方库函数冲突的时候可以使用库名区分。
示例代码:
// 自定义函数
func request(...)
// 第三方库函数
AF.request(...)
六、全局引入
以前 OC 常用pch
作为预编译头文件导入第三方库,在纯 Swift 中如果需要全局导入,可以借助 OC 的桥接头文件{TargetName}-Bridging-Header.h
。
示例代码:
#import <SwiftyJSON/SwiftyJSON-Swift.h>
#import <UIKit/UIKit.h>
一般情况下,库的导入格式是:库名-Swift.h
。当导入格式不正确时,可以进入framework
查看头文件名称。