iOS-Swift-标准库源码分析+项目实战

一. 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(
    _ transform: (Element) throws -> T
    ) rethrows -> [T] {
    let initialCapacity = underestimatedCount
    var result = ContiguousArray()
    result.reserveCapacity(initialCapacity)
    
    var iterator = self.makeIterator() //创建一个迭代器
    
    // Add elements up to the initial capacity without checking for regrowth.
    for _ in 0..

② flatMap

@inlinable
public func flatMap(
    _ 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()
    
    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(
    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(
    _ 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(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(
    _ 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(
    _ 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 ?? (optional: T?, defaultValue: @autoclosure () throws -> T)
        rethrows -> T {
            switch optional {
            case .some(let value):
                return value
            case .none:
                return try defaultValue()
            }
    }
    
    //左边右边都为T?会调用这个
    public func ?? (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
  • 导入第三方库(Framework形式):#import

你可能感兴趣的:(iOS-Swift-标准库源码分析+项目实战)