Swift系列三十五 - 源码和第三方库

2,071 阅读3分钟

Swift 于 2015 年正式开源。

一、目录简介

Githubgithub.com/apple/swift

几个可能会经常看的目录:

  • docs:一些文档
  • stdlib:Swift 源码
  • lib:C++源码
  • include:C++头文件

标准库源码位置: github.com/apple/swift…

二、Metadata 分析

文档:github.com/apple/swift…

2.1. 结构布局

类的前 8 个字节存储的就是类相关的信息,指向Metadata。那么Metadata存储的是什么呢(官方文档也没细说,只能从 Swift 源码看下相关描述)?

  1. Metadata是区分类型的,不同类型的Metadata是不同的(比如protocol、enum、class、struct、NSObject等等是不同的Metadata)。

  2. Metadata存储哪些内容和 ABI 有关,在 Swift5.0 的时候 ABI 已经稳定下来了(官方对应版本描述为 Stable)。而 ABI 稳定意味着Metadata结构已经稳定(比如 Swift2.0 的classMetadata结构中的第 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:github.com/Alamofire/A…

4.2. 图片缓存

Github:github.com/onevcat/Kin…

Kingfisher 默认不支持 WebP 格式的图片,需要额外安装 KingfisherWebP

pod 导入:

pod 'KingfisherWebP'

使用方法:

imageView.setImage(with: URL(string: user.avatar),
                   options: [.processor(WebPProcessor.default),
                             .cacheSerializer(WebPSerializer.default)])

4.3. JSON 访问

Github:github.com/SwiftyJSON/…

注意:该库仅仅是为了方便访问 JSON,而不是 JSON 转 Model

4.4. 字典转模型(JSON-Model)

Github:github.com/kakaopensou…

五、前缀

为防止和系统 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查看头文件名称。

至此,Swift所有章节已经更新完毕,更多系列文章,请关注 微信公众号【1024星球】(文章都会首发到公众号内)。