229_using_collections_effectively

0x0 protocol Collection

protocol Collection : Sequence {
    associatedtype Element
    associatedtype Index : Comparable
    //[x]取值語(yǔ)法糖
    subscript(position: Index) -> Element { get }
    //開(kāi)始下標(biāo)
    var startIndex: Index { get }
    //結(jié)束下標(biāo)
    var endIndex: Index { get }
    //根據(jù)下標(biāo)獲取元素
    func index(after i: Index) -> Index 
}   
  • Collection 有很多擴(kuò)展方法


    image.png
  • 集合協(xié)議繼承關(guān)系


    image.png
  • 下標(biāo)操作方式

//當(dāng)前下標(biāo)前一個(gè)下標(biāo)
func index(before: Self.Index) -> Self.Index
//當(dāng)前下標(biāo)后一個(gè)下標(biāo)
func index(after: Self.Index) -> Self.Index
  • 隨機(jī)訪問(wèn)集合
// constant time
//下標(biāo)偏移
func index(_ idx: Index, offsetBy n: Int) -> Index 
//兩個(gè)下標(biāo)的間距
func distance(from start: Index, to end: Index) -> Int
  • 集合類(lèi)型


    image.png

0x2 索引

//推薦使用
array.first 
set.first
  • 一個(gè)正確實(shí)現(xiàn)獲取集合第二個(gè)元素的的方法
extension Collection { 
    var second: Element? {
        // Is the collection empty?
        guard self.startIndex != self.endIndex else { return nil } 
        // Get the second index
        let index = self.index(after: self.startIndex)
        // Is that index valid?
        guard index != self.endIndex else { return nil } 
        // Return the second element
        return self[index]
    } 
}
  • 使用切片簡(jiǎn)化代碼
extension Collection { 
    var second: Element? {
        return self.dropFirst().first
    }
}
  • 使用切片簡(jiǎn)化代碼圖解


    image.png
  • 集合與切片對(duì)應(yīng)關(guān)系


    image.png
  • 切片會(huì)延長(zhǎng)集合生命周期

// Slicing Keeps Underlying Storage
extension Array {
    var firstHalf: ArraySlice<Element> {
        return self.dropLast(self.count / 2)
    } 
}
var array = [1, 2, 3, 4, 5, 6, 7, 8]
var firstHalf = array.firstHalf // [1, 2, 3, 4]
array = [] //釋放集合
print(firstHalf.first!)// 1
 
let copy = Array(firstHalf) // [1, 2, 3, 4] 拷貝切片以便后續(xù)使用
firstHalf = [] //釋放切片 保證集合可以釋放
print(copy.first!)// 1

0x3 lazy函數(shù)

let items = (1...4000).map { $0 * 2 }.filter { $0 < 10 } //立刻計(jì)算出值
let items = (1...4000).lazy.map { $0 * 2 }.filter { $0 < 10 } //用到的時(shí)候在去計(jì)算,每次都會(huì)重新計(jì)算
  • 加上lazy后每個(gè)類(lèi)型都用對(duì)應(yīng)的lazy對(duì)象進(jìn)行了嵌套


    image.png
  • 緩存lazy計(jì)算出的結(jié)果,保證lazy只執(zhí)行一次,不重復(fù)計(jì)算

let bears = ["Grizzly", "Panda", "Spectacled", "Gummy Bears", "Chicago"]
 
let redundantBears = bears.lazy.filter {
print("Checking '\($0)'")
}
return $0.contains("Bear")
 
let filteredBears = Array(redundantBears) // ["Gummy Bears"] //緩存結(jié)果
print(filteredBears.first!) // Gummy Bears
  • 使用lazy的建議
    使用lazy減少map和filter開(kāi)銷(xiāo)
    只需要部分運(yùn)算結(jié)果時(shí)
    避免在有副作用的閉包中使用
    避免API跨界???

0x4 可變集合與可區(qū)間替換集合

// constant time
subscript(_: Self.Index) -> Element { get set }
replaceSubrange(_:, with:)

0x5 為什么集合操作會(huì)crash

  • 兩步走
    1.你有修改集合嗎?
    2.你有在多線程中訪問(wèn)集合嗎?

  • crash案例

    總結(jié) 修改集合后索引下標(biāo)總是失效的,需要重新計(jì)算索引

  • 索引和切片使用建議
    小心使用索引和切片
    修改集合后會(huì)導(dǎo)致索引無(wú)效
    僅僅計(jì)算你需要的索引,有些集合計(jì)算索的時(shí)間時(shí)線性的
    切片使用時(shí)狀態(tài)依賴(lài)底層的原集合所以。所以在可變集合上使用切片需要仔細(xì)考慮

0x6 多線程

swift集合都是對(duì)單線程進(jìn)行優(yōu)化的
使用ThreadSanitizer 來(lái)檢測(cè)資源競(jìng)爭(zhēng)


image.png
  • 多線程編程建議
    盡量在一個(gè)線程修改狀態(tài)
    如果不行使用互斥的方式來(lái)解決(串行隊(duì)列,鎖)
    使用TSAN來(lái)檢查多線程競(jìng)爭(zhēng)問(wèn)題

  • 建議:推薦使用不可變集合
    因?yàn)榧蟽?nèi)容不會(huì)改變
    bug會(huì)少很多
    使用切片和lazy模擬狀態(tài)變化
    編譯器檢查提供幫助

  • 建議: 新建集合
    使用正確的容量來(lái)初始化集合,避免擴(kuò)容產(chǎn)生性能損耗,但是有不能帶太大避免過(guò)高的內(nèi)存占用

0x7 Foundation 集合

  • Objective-C的集合都是引用類(lèi)型的

  • 引用類(lèi)型的集合


    image.png
  • 引用類(lèi)型和值類(lèi)型的區(qū)別
    注意swift集合是寫(xiě)時(shí)copy 所以在修改集合之前 y引用了x


    image.png

    image.png
  • swift 中的 Objective-C APIs
    主要使用了bridge技術(shù)
    bridge的性能可能非常高效,但是記住永遠(yuǎn)不如swift內(nèi)通信高效

  • lazy bridge 和 eager bridge
    其中NSView時(shí)lazy bridge 用時(shí)才會(huì)發(fā)生bridge轉(zhuǎn)換,其他的由于類(lèi)型不同,需要立刻bridge轉(zhuǎn)換


    image.png
  • bridge常見(jiàn)的問(wèn)題
    使用instruments 測(cè)量性能 特別注意跨語(yǔ)言邊界這一塊
    避免在循環(huán)內(nèi)部使用bridge
    as NSString 可以避免bridge轉(zhuǎn)換

  • 何時(shí)使用Foundation集合
    當(dāng)你需要使用引用類(lèi)型時(shí)
    當(dāng)使用 NSAttributedString.string時(shí)
    當(dāng)使用 Core Data Managed Objects時(shí)
    當(dāng)你確定bridge會(huì)耗費(fèi)過(guò)多性能時(shí)

?著作權(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)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,626評(píng)論 1 32
  • 朋友們聚在一起,聊到夫妻關(guān)系一章,有怨言,有癡語(yǔ),有默然,有莞爾,各種感悟,各說(shuō)紛紜,說(shuō)不盡夫妻之間愛(ài)、嗔、...
    瑞雪晴天閱讀 273評(píng)論 0 3
  • iiOS10添加了新的權(quán)限控制范圍 如果你嘗試訪問(wèn)這些隱私數(shù)據(jù)時(shí)得到如下錯(cuò)誤: > This app has cr...
    深藏不露的zack閱讀 903評(píng)論 0 0
  • 大二這第一學(xué)期過(guò)得很快,我靜下心來(lái)回想自己這十幾周來(lái)做過(guò)的種種事情。 從開(kāi)學(xué)的社團(tuán)成立大會(huì),之后招新,隨之一起...
    奈奈巫閱讀 215評(píng)論 0 0
  • 作為一個(gè)大齡單身女中年,下班之后閑極無(wú)聊,隨著欣賞水平的提高,很難看進(jìn)去一部劇或者小說(shuō),沒(méi)事情做感到有些心慌慌...
    余步閱讀 207評(píng)論 0 0

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