一. Swift源码简介
Swift于2015年正式开源,github地址: https://github.com/apple/swift
几个可能会经常看的目录:
docs:一些文档
stdlib:Swift源码
lib:C++源码
include:C++头文件
标准库源码位置:https://github.com/apple/swift/tree/master/stdlib/public/core
1. Array分析
https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift
① map
@inlinable
public func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
let initialCapacity = underestimatedCount
var result = ContiguousArray<T>()
result.reserveCapacity(initialCapacity)
var iterator = self.makeIterator() //创建一个迭代器
// Add elements up to the initial capacity without checking for regrowth.
for _ in 0..<initialCapacity {
result.append(try transform(iterator.next()!))
}
// Add remaining elements, if any.
while let element = iterator.next() { //利用迭代器遍历数组中的元素
result.append(try transform(element)) //拿到元素,传到闭包里面,闭包表达式返回的结果放到数组里面
}
return Array(result) //返回结果数组
}
② flatMap
@inlinable
public func flatMap<SegmentOfResult: Sequence>(
_ transform: (Element) throws -> SegmentOfResult
) rethrows -> [SegmentOfResult.Element] {
var result: [SegmentOfResult.Element] = []
for element in self { //遍历数组中的每一个元素
//将数组元素传给闭包表达式,调用闭包表达式,将闭包表达式的返回结果拼接到数组中
//通过contentsOf可以看出,如果返回结果是数组,会将数组的内容取出来拼接到数组中,这也是flatMap和map的区别
result.append(contentsOf: try transform(element))
}
return result
}
}
③ filter
@inlinable
public __consuming func filter(
_ isIncluded: (Element) throws -> Bool
) rethrows -> [Element] {
return try _filter(isIncluded)
}
@_transparent
public func _filter(
_ isIncluded: (Element) throws -> Bool
) rethrows -> [Element] {
var result = ContiguousArray<Element>()
var iterator = self.makeIterator() //创建一个迭代器
while let element = iterator.next() {
if try isIncluded(element) { //拿到元素,传到闭包里面,调用闭包,返回true就把元素放到数组里面去
result.append(element) //返回数组
}
}
return Array(result)
}
https://github.com/apple/swift/blob/master/stdlib/public/core/SequenceAlgorithms.swift
④ reduce
@inlinable
public func reduce<Result>(
into initialResult: __owned Result,
_ updateAccumulatingResult:
(_ partialResult: inout Result, Element) throws -> ()
) rethrows -> Result {
var accumulator = initialResult
for element in self { //遍历元素
//将元素和上一次的结果传进来,调用闭包表达式,返回一个结果,再把这个结果传给下一个闭包
try updateAccumulatingResult(&accumulator, element)
}
return accumulator
}
}
⑤ compactMap
@inlinable // protocol-only
@inline(__always)
public func _compactMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
var result: [ElementOfResult] = []
for element in self { //遍历
//对闭包表达式的返回值做一个可选绑定,不为空才拼接到数组
if let newElement = try transform(element) {
result.append(newElement)
}
}
return result
}
}
2. Substring分析
https://github.com/apple/swift/blob/master/stdlib/public/core/Substring.swift
① append
@inlinable // specialize
public mutating func append<S: Sequence>(contentsOf elements: S)
where S.Element == Character {
var string = String(self) //将Substring传进去创建一个新的string
self = Substring() // Keep unique storage if possible
string.append(contentsOf: elements) //再用新的string拼接
self = Substring(string) //再将新的string转成Substring
}
}
② lowercased、uppercased
public func lowercased() -> String {
return String(self).lowercased() //先转成String,再调用lowercased()方法
}
public func uppercased() -> String {
return String(self).uppercased()
}
3. Optional分析
https://github.com/apple/swift/blob/master/stdlib/public/core/Optional.swift
① map、flatMap
@inlinable
public func map<U>(
_ transform: (Wrapped) throws -> U
) rethrows -> U? {
switch self {
//如果不为nil,就解包将解包之后的值传入闭包表达式。再将闭包表达式的返回值包装成可选类型,然后返回出去
case .some(let y):
return .some(try transform(y))
case .none: //如果为nil就返回nil
return .none
}
}
@inlinable
public func flatMap<U>(
_ transform: (Wrapped) throws -> U?
) rethrows -> U? {
switch self {
case .some(let y):
//直接返回,并没有包装成可选类型(区别:map会包装一层可选类型,flatMap不会包装)
return try transform(y)
case .none:
return .none
}
}
② 等价运算符 ==
关于等价运算符可以参考之前的文章iOS-Swift-高级运算符
extension Optional where Wrapped: Equatable {
//左边为nil右边为可选类型会进入这里
public static func ==(lhs: _OptionalNilComparisonType, rhs: Wrapped?) -> Bool {
switch rhs {
case .some:
return false
case .none:
return true
}
}
//左边为可选类型右边为nil会进入这里
public static func ==(lhs: Wrapped?, rhs: _OptionalNilComparisonType) -> Bool {
switch lhs {
case .some:
return false
case .none:
return true
}
}
//左右都为可选类型会进入这里(如果有非可选的会被包装成可选的,如:Int->Int?)
//如果两个都为可选类型,进入这个方法的时候会把两个参数包装成?多的那个
public static func ==(lhs: Wrapped?, rhs: Wrapped?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?): //左右都不为nil 解包,将解包后的值赋值给l和r
return l == r //l和r相等就返回true
case (nil, nil): //左右都为nil
return true
default: //其他情况
return false
}
}
}
var age1: Int???? = 20
var age2: Int = 20
print(age1 == age2) //true 都会包装成Int????
var age3: Int? = nil
var age4: Int??? = age3
var age5: Int??? = nil
print(age4 == age5) //false age4和age5不一样,age5盒子里就一个nil,age4盒子里不为nil,装了个age3,age3里面才是nil,所以他们不相等
var age6: Int??? = nil
var age7: Int? = nil
print(age6 == age7) //false 这时候比较的时候会进入default,一个为nil一个不为nil,换个思路,类型不一样肯定不相等啊
③ 空合并运算符 ??
关于空合并运算符可以参考之前的文章iOS-Swift-可选项
extension Optional where Wrapped: Equatable {
//左边为T?右边为T会调用这个
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)
rethrows -> T {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
//左边右边都为T?会调用这个
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?)
rethrows -> T? {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
}
var age1: Int? = 10
var age2: Int? = 20
print(age1 ?? age2)
//这时候T?就是Int?,T就是Int
//会调用第二个,最后返回值是T?类型,所以返回Optional(10)
var age3: Int??? = 10
var age4: Int? = 20
print(age3 ?? age4)
//这时候T?就是Int???,T就是Int??
//会调用第一个,最后返回值是T类型,所以返回(Optional(Optional(10)))
var age5: Int??? = nil
var age6: Int? = 20
print(age5 ?? age6)
//这时候T?就是Int???,T就是Int??
//会调用第一个,最后返回值是T类型,所以返回(Optional(Optional(20)))
4. Metadata分析
Swift的类内存结构是:
前8个字节放metadata类型相关,后8个字节放指针相关,后⾯再放成员变量信息。
如果继承于NSObject,内存信息就变成了:前8个字节放isa指针相关,后⾯再放成员变量信息。
那么metadata里面放的是什么呢?
metadata里面放的东西跟ABI有关,如果ABI稳定了,metadata⾥⾯的东西就定型了。Swift5之后ABI就稳定了,所以metadata里面放的东西不会有大改变了。
metadata文档如下:
文档:https://github.com/apple/swift/blob/master/docs/ABI/TypeMetadata.rst
其他参考:
https://github.com/apple/swift/blob/master/include/swift/ABI/Metadata.h https://github.com/apple/swift/blob/master/include/swift/ABI/MetadataKind.def https://github.com/apple/swift/blob/master/include/swift/ABI/MetadataValues.h https://github.com/apple/swift/blob/master/include/swift/Reflection/Records.h
metadata有什么用呢?
通过metadata就能找到这个类型中有哪些成员,以前OC是通过Runtime的class_copyIvarList获取的,但是纯Swift类不⽀持,Swift是通过metadata获取的,之后就能进⾏JSON<->Model互转(例如MJ老师的KakaJSON)。
关于KakaJSON:
根据上面的metadata文档也可以弄清楚metadata里面的布局,但是比较麻烦。MJ老师的KakaJSON框架的Metadata->Layout文件夹下面存放的就是Metadata的布局,更直观。
5. 反射
反射是编程语言中一项强大的能力,比如Java语言的反射机制。
- 对于任意一个类型,都能够动态获取这个类的所有属性和方法信息。
- 对于任意一个实例,都能够动态获取、调用它的任意属性和方法。
Swift的反射机制目前还比较弱,通过Mirror类型来提供简单的反射功能
struct Person {
var age: Int = 0
var name: String = ""
}
let mirror = Mirror(reflecting: Person(age: 10, name: "Jack"))
// struct
print(mirror.displayStyle!) //是结构体还是类
// Person
print(mirror.subjectType) //名称是什么
// nil
print(mirror.superclassMirror as Any) //父类的Mirror是什么
// age 10
// name Jack
for case let (label?, value) in mirror.children { //遍历属性
print(label, value)
}
如果Swift的反射机制已经很强大了,MJ老师的KakaJSON框架就不用自己写Metadata的布局了,直接使用Mirror类型就可以知道类型中有哪些成员了。
二. 项目实战
1. 常用Swift第三方库
网络请求:https://github.com/Alamofire/Alamofire
图片下载:https://github.com/onevcat/Kingfisher
JSON访问:https://github.com/SwiftyJSON/SwiftyJSON
JSON-Model转换:https://github.com/kakaopensource/KakaJSON
补充:
Alamofire的request方法可以直接使用,不像以前需要创建实例,这是为什么呢?
因为request是public的,其他模块也可以使用。
如果自己也有request方法,想要使用Alamofire的request方法,就直接Alamofire.request就可以了,所以现在好多第三方库的方法都是直接public的,也不怕重名。
2. Kingfisher注意点
Kingfisher默认不支持WebP格式的图片,需要额外安装KingfisherWebP
pod 'KingfisherWebP'
iconView.kf.setImage(with: URL(string: user.thumb),
options: [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)])
3. 库的导入问题
默认情况下,用到哪个库就要导入哪个库,无疑增加了很多重复的工作量,如何办到全局导入库?
新建一个用于Swift调用OC的桥接文件:targetName-Bridging-Header.h
- 导入系统库:#import <XX/XX.h>
- 导入第三方库(Framework形式):#import <XX/XX-Swift.h>