一. 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>