iOS-Swift-標(biāo)準(zhǔn)庫(kù)源碼分析+項(xiàng)目實(shí)戰(zhàn)

一. Swift源碼簡(jiǎn)介

Swift于2015年正式開(kāi)源,github地址: https://github.com/apple/swift

幾個(gè)可能會(huì)經(jīng)??吹哪夸洠?br> docs:一些文檔
stdlib:Swift源碼
lib:C++源碼
include:C++頭文件

標(biāo)準(zhǔn)庫(kù)源碼位置: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() //創(chuàng)建一個(gè)迭代器
    
    // 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() { //利用迭代器遍歷數(shù)組中的元素
        result.append(try transform(element)) //拿到元素,傳到閉包里面,閉包表達(dá)式返回的結(jié)果放到數(shù)組里面
    }
    return Array(result) //返回結(jié)果數(shù)組
}

② flatMap

@inlinable
public func flatMap<SegmentOfResult: Sequence>(
    _ transform: (Element) throws -> SegmentOfResult
    ) rethrows -> [SegmentOfResult.Element] {
    var result: [SegmentOfResult.Element] = []
    for element in self { //遍歷數(shù)組中的每一個(gè)元素
        //將數(shù)組元素傳給閉包表達(dá)式,調(diào)用閉包表達(dá)式,將閉包表達(dá)式的返回結(jié)果拼接到數(shù)組中
        //通過(guò)contentsOf可以看出,如果返回結(jié)果是數(shù)組,會(huì)將數(shù)組的內(nèi)容取出來(lái)拼接到數(shù)組中,這也是flatMap和map的區(qū)別
        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() //創(chuàng)建一個(gè)迭代器
    
    while let element = iterator.next() {
        if try isIncluded(element) { //拿到元素,傳到閉包里面,調(diào)用閉包,返回true就把元素放到數(shù)組里面去
            result.append(element) //返回?cái)?shù)組
        }
    }
    
    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 { //遍歷元素
        //將元素和上一次的結(jié)果傳進(jìn)來(lái),調(diào)用閉包表達(dá)式,返回一個(gè)結(jié)果,再把這個(gè)結(jié)果傳給下一個(gè)閉包
        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 { //遍歷
        //對(duì)閉包表達(dá)式的返回值做一個(gè)可選綁定,不為空才拼接到數(shù)組
        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傳進(jìn)去創(chuàng)建一個(gè)新的string
        self = Substring() // Keep unique storage if possible
        string.append(contentsOf: elements) //再用新的string拼接
        self = Substring(string) //再將新的string轉(zhuǎn)成Substring
  }
}

② lowercased、uppercased

public func lowercased() -> String {
    return String(self).lowercased() //先轉(zhuǎn)成String,再調(diào)用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,就解包將解包之后的值傳入閉包表達(dá)式。再將閉包表達(dá)式的返回值包裝成可選類型,然后返回出去
    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):
        //直接返回,并沒(méi)有包裝成可選類型(區(qū)別:map會(huì)包裝一層可選類型,flatMap不會(huì)包裝)
        return try transform(y) 
    case .none:
        return .none
    }
}

② 等價(jià)運(yùn)算符 ==

關(guān)于等價(jià)運(yùn)算符可以參考之前的文章iOS-Swift-高級(jí)運(yùn)算符

extension Optional where Wrapped: Equatable {
    //左邊為nil右邊為可選類型會(huì)進(jìn)入這里
    public static func ==(lhs: _OptionalNilComparisonType, rhs: Wrapped?) -> Bool {
        switch rhs {
        case .some:
            return false
        case .none:
            return true
        }
    }
    //左邊為可選類型右邊為nil會(huì)進(jìn)入這里
    public static func ==(lhs: Wrapped?, rhs: _OptionalNilComparisonType) -> Bool {
        switch lhs {
        case .some:
            return false
        case .none:
            return true
        }
    }
    //左右都為可選類型會(huì)進(jìn)入這里(如果有非可選的會(huì)被包裝成可選的,如:Int->Int?)
    //如果兩個(gè)都為可選類型,進(jìn)入這個(gè)方法的時(shí)候會(huì)把兩個(gè)參數(shù)包裝成?多的那個(gè)
    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 都會(huì)包裝成Int????

var age3: Int? = nil
var age4: Int??? = age3
var age5: Int??? = nil
print(age4 == age5) //false age4和age5不一樣,age5盒子里就一個(gè)nil,age4盒子里不為nil,裝了個(gè)age3,age3里面才是nil,所以他們不相等

var age6: Int??? = nil
var age7: Int? = nil
print(age6 == age7) //false 這時(shí)候比較的時(shí)候會(huì)進(jìn)入default,一個(gè)為nil一個(gè)不為nil,換個(gè)思路,類型不一樣肯定不相等啊

③ 空合并運(yùn)算符 ??

關(guān)于空合并運(yùn)算符可以參考之前的文章iOS-Swift-可選項(xiàng)

extension Optional where Wrapped: Equatable {
    //左邊為T(mén)?右邊為T(mén)會(huì)調(diào)用這個(gè)
    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(mén)?會(huì)調(diào)用這個(gè)
    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)
//這時(shí)候T?就是Int?,T就是Int
//會(huì)調(diào)用第二個(gè),最后返回值是T?類型,所以返回Optional(10)

var age3: Int??? = 10
var age4: Int? = 20
print(age3 ?? age4)
//這時(shí)候T?就是Int???,T就是Int??
//會(huì)調(diào)用第一個(gè),最后返回值是T類型,所以返回(Optional(Optional(10)))

var age5: Int??? = nil
var age6: Int? = 20
print(age5 ?? age6)
//這時(shí)候T?就是Int???,T就是Int??
//會(huì)調(diào)用第一個(gè),最后返回值是T類型,所以返回(Optional(Optional(20)))

4. Metadata分析

Swift的類內(nèi)存結(jié)構(gòu)是:
前8個(gè)字節(jié)放metadata類型相關(guān),后8個(gè)字節(jié)放指針相關(guān),后?再放成員變量信息。
如果繼承于NSObject,內(nèi)存信息就變成了:前8個(gè)字節(jié)放isa指針相關(guān),后?再放成員變量信息。

那么metadata里面放的是什么呢?
metadata里面放的東西跟ABI有關(guān),如果ABI穩(wěn)定了,metadata??的東西就定型了。Swift5之后ABI就穩(wěn)定了,所以metadata里面放的東西不會(huì)有大改變了。

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有什么用呢?
通過(guò)metadata就能找到這個(gè)類型中有哪些成員,以前OC是通過(guò)Runtime的class_copyIvarList獲取的,但是純Swift類不?持,Swift是通過(guò)metadata獲取的,之后就能進(jìn)?JSON<->Model互轉(zhuǎn)(例如MJ老師的KakaJSON)。

關(guān)于KakaJSON:
根據(jù)上面的metadata文檔也可以弄清楚metadata里面的布局,但是比較麻煩。MJ老師的KakaJSON框架的Metadata->Layout文件夾下面存放的就是Metadata的布局,更直觀。

5. 反射

反射是編程語(yǔ)言中一項(xiàng)強(qiáng)大的能力,比如Java語(yǔ)言的反射機(jī)制。

  • 對(duì)于任意一個(gè)類型,都能夠動(dòng)態(tài)獲取這個(gè)類的所有屬性和方法信息。
  • 對(duì)于任意一個(gè)實(shí)例,都能夠動(dòng)態(tài)獲取、調(diào)用它的任意屬性和方法。

Swift的反射機(jī)制目前還比較弱,通過(guò)Mirror類型來(lái)提供簡(jiǎn)單的反射功能

struct Person {
    var age: Int = 0
    var name: String = ""
}

let mirror = Mirror(reflecting: Person(age: 10, name: "Jack"))
// struct
print(mirror.displayStyle!) //是結(jié)構(gòu)體還是類
// 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的反射機(jī)制已經(jīng)很強(qiáng)大了,MJ老師的KakaJSON框架就不用自己寫(xiě)Metadata的布局了,直接使用Mirror類型就可以知道類型中有哪些成員了。

二. 項(xiàng)目實(shí)戰(zhàn)

1. 常用Swift第三方庫(kù)

網(wǎng)絡(luò)請(qǐng)求:https://github.com/Alamofire/Alamofire
圖片下載:https://github.com/onevcat/Kingfisher
JSON訪問(wèn):https://github.com/SwiftyJSON/SwiftyJSON
JSON-Model轉(zhuǎn)換:https://github.com/kakaopensource/KakaJSON

補(bǔ)充:
Alamofire的request方法可以直接使用,不像以前需要?jiǎng)?chuàng)建實(shí)例,這是為什么呢?
因?yàn)閞equest是public的,其他模塊也可以使用。

如果自己也有request方法,想要使用Alamofire的request方法,就直接Alamofire.request就可以了,所以現(xiàn)在好多第三方庫(kù)的方法都是直接public的,也不怕重名。

2. Kingfisher注意點(diǎn)

Kingfisher默認(rèn)不支持WebP格式的圖片,需要額外安裝KingfisherWebP

pod 'KingfisherWebP'
iconView.kf.setImage(with: URL(string: user.thumb),
                     options: [.processor(WebPProcessor.default), .cacheSerializer(WebPSerializer.default)])

3. 庫(kù)的導(dǎo)入問(wèn)題

默認(rèn)情況下,用到哪個(gè)庫(kù)就要導(dǎo)入哪個(gè)庫(kù),無(wú)疑增加了很多重復(fù)的工作量,如何辦到全局導(dǎo)入庫(kù)?

新建一個(gè)用于Swift調(diào)用OC的橋接文件:targetName-Bridging-Header.h

  • 導(dǎo)入系統(tǒng)庫(kù):#import <XX/XX.h>
  • 導(dǎo)入第三方庫(kù)(Framework形式):#import <XX/XX-Swift.h>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容