【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】【基本功】深入剖析Swift性能優(yōu)化_第1頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】【基本功】深入剖析Swift性能優(yōu)化_第2頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】【基本功】深入剖析Swift性能優(yōu)化_第3頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】【基本功】深入剖析Swift性能優(yōu)化_第4頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】【基本功】深入剖析Swift性能優(yōu)化_第5頁(yè)
已閱讀5頁(yè),還剩10頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】【基本功】深入剖析Swift性能優(yōu)化

美美今天請(qǐng)來(lái)了我們技術(shù)團(tuán)隊(duì)很厲害的iOS女神亞男小姐姐深度剖析Swift,她特別講解了如何才能開(kāi)發(fā)出高性能的Swift程序。希望對(duì)你有所幫助哦~EnjoyReading!簡(jiǎn)介2014年,蘋果公司在WWDC上發(fā)布Swift這一新的編程語(yǔ)言。經(jīng)過(guò)幾年的發(fā)展,Swift已經(jīng)成為iOS開(kāi)發(fā)語(yǔ)言的“中流砥柱”,Swift提供了非常靈活的高級(jí)別特性,例如協(xié)議、閉包、泛型等,并且Swift還進(jìn)一步開(kāi)發(fā)了強(qiáng)大的SIL(SwiftIntermediateLanguage)用于對(duì)編譯器進(jìn)行優(yōu)化,使得Swift相比Objective-C運(yùn)行更快性能更優(yōu),Swift內(nèi)部如何實(shí)現(xiàn)性能的優(yōu)化,我們本文就進(jìn)行一下解讀,希望能對(duì)大家有所啟發(fā)和幫助。針對(duì)Swift性能提升這一問(wèn)題,我們可以從概念上拆分為兩個(gè)部分:編譯器:Swift編譯器進(jìn)行的性能優(yōu)化,從階段分為編譯期和運(yùn)行期,內(nèi)容分為時(shí)間優(yōu)化和空間優(yōu)化。開(kāi)發(fā)者:通過(guò)使用合適的數(shù)據(jù)結(jié)構(gòu)和關(guān)鍵字,幫助編譯器獲取更多信息,進(jìn)行優(yōu)化。下面我們將從這兩個(gè)角度切入,對(duì)Swift性能優(yōu)化進(jìn)行分析。通過(guò)了解編譯器對(duì)不同數(shù)據(jù)結(jié)構(gòu)處理的內(nèi)部實(shí)現(xiàn),來(lái)選擇最合適的算法機(jī)制,并利用編譯器的優(yōu)化特性,編寫高性能的程序。理解Swift的性能,首先要清楚Swift的數(shù)據(jù)結(jié)構(gòu),組件關(guān)系和編譯運(yùn)行方式。數(shù)據(jù)結(jié)構(gòu)Swift的數(shù)據(jù)結(jié)構(gòu)可以大體拆分為:Class,Struct,Enum。組件關(guān)系組件關(guān)系可以分為:inheritance,protocols,generics。方法分派方式方法分派方式可以分為Staticdispatch和Dynamicdispatch。要在開(kāi)發(fā)中提高Swift性能,需要開(kāi)發(fā)者去了解這幾種數(shù)據(jù)結(jié)構(gòu)和組件關(guān)系以及它們的內(nèi)部實(shí)現(xiàn),從而通過(guò)選擇最合適的抽象機(jī)制來(lái)提升性能。首先我們對(duì)于性能標(biāo)準(zhǔn)進(jìn)行一個(gè)概念陳述,性能標(biāo)準(zhǔn)涵蓋三個(gè)標(biāo)準(zhǔn):AllocationReferencecountingMethoddispatch接下來(lái),我們會(huì)分別對(duì)這幾個(gè)指標(biāo)進(jìn)行說(shuō)明。內(nèi)存分配可以分為堆區(qū)棧區(qū),在棧的內(nèi)存分配速度要高于堆,結(jié)構(gòu)體和類在堆棧分配是不同的。Stack基本數(shù)據(jù)類型和結(jié)構(gòu)體默認(rèn)在棧區(qū),棧區(qū)內(nèi)存是連續(xù)的,通過(guò)出棧入棧進(jìn)行分配和銷毀,速度很快,高于堆區(qū)。我們通過(guò)一些例子進(jìn)行說(shuō)明:以上結(jié)構(gòu)體的內(nèi)存是在棧區(qū)分配的,內(nèi)部的變量也是內(nèi)聯(lián)在棧區(qū)。將point1賦值給point2實(shí)際操作是在棧區(qū)進(jìn)行了一份拷貝,產(chǎn)生了新的內(nèi)存消耗point2,這使得point1和point2是完全獨(dú)立的兩個(gè)實(shí)例,它們之間的操作互不影響。在使用point1和point2之后,會(huì)進(jìn)行銷毀。Heap高級(jí)的數(shù)據(jù)結(jié)構(gòu),比如類,分配在堆區(qū)。初始化時(shí)查找沒(méi)有使用的內(nèi)存塊,銷毀時(shí)再?gòu)膬?nèi)存塊中清除。因?yàn)槎褏^(qū)可能存在多線程的操作問(wèn)題,為了保證線程安全,需要進(jìn)行加鎖操作,因此也是一種性能消耗。以上我們初始化了一個(gè)Class類型,在棧區(qū)分配一塊內(nèi)存,但是和結(jié)構(gòu)體直接在棧內(nèi)存儲(chǔ)數(shù)值不同,我們只在棧區(qū)存儲(chǔ)了對(duì)象的指針,指針指向的對(duì)象的內(nèi)存是分配在堆區(qū)的。需要注意的是,為了管理對(duì)象內(nèi)存,在堆區(qū)初始化時(shí),除了分配屬性內(nèi)存(這里是Double類型的x,y),還會(huì)有額外的兩個(gè)字段,分別是type和refCount,這個(gè)包含了type,refCount和實(shí)際屬性的結(jié)構(gòu)被稱為bluebox。內(nèi)存分配總結(jié)從初始化角度,Class相比Struct需要在堆區(qū)分配內(nèi)存,進(jìn)行內(nèi)存管理,使用了指針,有更強(qiáng)大的特性,但是性能較低。優(yōu)化方式:對(duì)于頻繁操作(比如通信軟件的內(nèi)容氣泡展示),盡量使用Struct替代Class,因?yàn)闂?nèi)存分配更快,更安全,操作更快。Swift通過(guò)引用計(jì)數(shù)管理堆對(duì)象內(nèi)存,當(dāng)引用計(jì)數(shù)為0時(shí),Swift確認(rèn)沒(méi)有對(duì)象再引用該內(nèi)存,所以將內(nèi)存釋放。對(duì)于引用計(jì)數(shù)的管理是一個(gè)非常高頻的間接操作,并且需要考慮線程安全,使得引用計(jì)數(shù)的操作需要較高的性能消耗。對(duì)于基本數(shù)據(jù)類型的Struct來(lái)說(shuō),沒(méi)有堆內(nèi)存分配和引用計(jì)數(shù)的管理,性能更高更安全,但是對(duì)于復(fù)雜的結(jié)構(gòu)體,如:這里看到,包含了引用的結(jié)構(gòu)體相比Class,需要管理雙倍的引用計(jì)數(shù)。每次將結(jié)構(gòu)體作為參數(shù)傳遞給方法或者進(jìn)行直接拷貝時(shí),都會(huì)出現(xiàn)多份引用計(jì)數(shù)。下圖可以比較直觀的理解:Class在拷貝時(shí)的處理方式:引用計(jì)數(shù)總結(jié)Class在堆區(qū)分配內(nèi)存,需要使用引用計(jì)數(shù)器進(jìn)行內(nèi)存管理?;绢愋偷腟truct在棧區(qū)分配內(nèi)存,無(wú)引用計(jì)數(shù)管理。包含強(qiáng)類型的Struct通過(guò)指針管理在堆區(qū)的屬性,對(duì)結(jié)構(gòu)體的拷貝會(huì)創(chuàng)建新的棧內(nèi)存,創(chuàng)建多份引用的指針,Class只會(huì)有一份。優(yōu)化方式在使用結(jié)構(gòu)體時(shí):通過(guò)使用精確類型,例如UUID替代String(UUID字節(jié)長(zhǎng)度固定128字節(jié),而不是String任意長(zhǎng)度),這樣就可以進(jìn)行內(nèi)存內(nèi)聯(lián),在棧內(nèi)存儲(chǔ)UUID,我們知道,棧內(nèi)存管理更快更安全,并且不需要引用計(jì)數(shù)。Enum替代String,在棧內(nèi)管理內(nèi)存,無(wú)引用計(jì)數(shù),并且從語(yǔ)法上對(duì)于開(kāi)發(fā)者更友好。我們之前在StaticdispatchVSDynamicdispatch中提到過(guò),能夠在編譯期確定執(zhí)行方法的方式叫做靜態(tài)分派Staticdispatch,無(wú)法在編譯期確定,只能在運(yùn)行時(shí)去確定執(zhí)行方法的分派方式叫做動(dòng)態(tài)分派Dynamicdispatch。Staticdispatch更快,而且靜態(tài)分派可以進(jìn)行內(nèi)聯(lián)等進(jìn)一步的優(yōu)化,使得執(zhí)行更快速,性能更高。但是對(duì)于多態(tài)的情況,我們不能在編譯期確定最終的類型,這里就用到了Dynamicdispatch動(dòng)態(tài)分派。動(dòng)態(tài)分派的實(shí)現(xiàn)是,每種類型都會(huì)創(chuàng)建一張表,表內(nèi)是一個(gè)包含了方法指針的數(shù)組。動(dòng)態(tài)分派更靈活,但是因?yàn)橛胁楸砗吞D(zhuǎn)的操作,并且因?yàn)楹芏嗵攸c(diǎn)對(duì)于編譯器來(lái)說(shuō)并不明確,所以相當(dāng)于block了編譯器的一些后期優(yōu)化。所以速度慢于Staticdispatch。下面看一段多態(tài)代碼,以及分析實(shí)現(xiàn)方式:MethodDispatch總結(jié)Class默認(rèn)使用Dynamicdispatch,因?yàn)樵诰幾g期幾乎每個(gè)環(huán)節(jié)的信息都無(wú)法確定,所以阻礙了編譯器的優(yōu)化,比如inline和wholemoduleinline。使用Staticdispatch代替Dynamicdispatch提升性能我們知道Staticdispatch快于Dynamicdispatch,如何在開(kāi)發(fā)中去盡可能使用Staticdispatch。inheritanceconstraints繼承約束我們可以使用final關(guān)鍵字去修飾Class,以此生成的Finalclass,使用Staticdispatch。accesscontrol訪問(wèn)控制private關(guān)鍵字修飾,使得方法或?qū)傩灾粚?duì)當(dāng)前類可見(jiàn)。編譯器會(huì)對(duì)方法進(jìn)行Staticdispatch。編譯器可以通過(guò)wholemoduleoptimization檢查繼承關(guān)系,對(duì)某些沒(méi)有標(biāo)記final的類通過(guò)計(jì)算,如果能在編譯期確定執(zhí)行的方法,則使用Staticdispatch。Struct默認(rèn)使用Staticdispatch。Swift快于OC的一個(gè)關(guān)鍵是可以消解動(dòng)態(tài)分派??偨Y(jié)Swift提供了更靈活的Struct,用以在內(nèi)存、引用計(jì)數(shù)、方法分派等角度去進(jìn)行性能的優(yōu)化,在正確的時(shí)機(jī)選擇正確的數(shù)據(jù)結(jié)構(gòu),可以使我們的代碼性能更快更安全。延伸你可能會(huì)問(wèn)Struct如何實(shí)現(xiàn)多態(tài)呢?答案是protocolorientedprogramming。以上分析了影響性能的幾個(gè)標(biāo)準(zhǔn),那么不同的算法機(jī)制Class,ProtocolTypes和Genericcode,它們?cè)谶@三方面的表現(xiàn)如何,ProtocolType和Genericcode分別是怎么實(shí)現(xiàn)的呢?我們帶著這個(gè)問(wèn)題看下去。這里我們會(huì)討論P(yáng)rotocolType如何存儲(chǔ)和拷貝變量,以及方法分派是如何實(shí)現(xiàn)的。不通過(guò)繼承或者引用語(yǔ)義的多態(tài):以上通過(guò)ProtocolType實(shí)現(xiàn)多態(tài),幾個(gè)類之間沒(méi)有繼承關(guān)系,故不能按照慣例借助V-Table實(shí)現(xiàn)動(dòng)態(tài)分派。如果想了解Vtable和Witnesstable實(shí)現(xiàn),可以進(jìn)行點(diǎn)擊查看,這里不做細(xì)節(jié)說(shuō)明。因?yàn)镻oint和Line的尺寸不同,數(shù)組存儲(chǔ)數(shù)據(jù)實(shí)現(xiàn)一致性存儲(chǔ),使用了ExistentialContainer。查找正確的執(zhí)行方法則使用了ProtolocWitnessTable。ExistentialContainer是一種特殊的內(nèi)存布局方式,用于管理遵守了相同協(xié)議的數(shù)據(jù)類型ProtocolType,這些數(shù)據(jù)類型因?yàn)椴还蚕硗焕^承關(guān)系(這是V-Table實(shí)現(xiàn)的前提),并且內(nèi)存空間尺寸不同,使用ExistentialContainer進(jìn)行管理,使其具有存儲(chǔ)的一致性。結(jié)構(gòu)如下:三個(gè)詞大小的valueBuffer這里介紹一下valueBuffer結(jié)構(gòu),valueBuffer有三個(gè)詞,每個(gè)詞包含8個(gè)字節(jié),存儲(chǔ)的可能是值,也可能是對(duì)象的指針。對(duì)于smallvalue(空間小于valueBuffer),直接存儲(chǔ)在valueBuffer的地址內(nèi),inlinevalueBuffer,無(wú)額外堆內(nèi)存初始化。當(dāng)值的數(shù)量大于3個(gè)屬性即largevalue,或者總尺寸超過(guò)valueBuffer的占位,就會(huì)在堆區(qū)開(kāi)辟內(nèi)存,將其存儲(chǔ)在堆區(qū),valueBuffer存儲(chǔ)內(nèi)存指針。valuewitnesstable的引用因?yàn)镻rotocolType的類型不同,內(nèi)存空間,初始化方法等都不相同,為了對(duì)ProtocolType生命周期進(jìn)行專項(xiàng)管理,用到了ValueWitnessTtocolwitnesstable的引用管理ProtocolType的方法分派。內(nèi)存分布如下:為了實(shí)現(xiàn)Class多態(tài)也就是引用語(yǔ)義多態(tài),需要V-Table來(lái)實(shí)現(xiàn),但是V-Table的前提是具有同一個(gè)父類即共享相同的繼承關(guān)系,但是對(duì)于ProtocolType來(lái)說(shuō),并不具備此特征,故為了支持Struct的多態(tài),需要用到protocolorientedprogramming機(jī)制,也就是借助ProtocolWitnessTable來(lái)實(shí)現(xiàn)(細(xì)節(jié)可以點(diǎn)擊Vtable和witnesstable實(shí)現(xiàn),每個(gè)結(jié)構(gòu)體會(huì)創(chuàng)造PWT表,內(nèi)部包含指針,指向方法具體實(shí)現(xiàn))。用于管理任意值的初始化、拷貝、銷毀。ValueWitnessTable的結(jié)構(gòu)如上,是用于管理遵守了協(xié)議的ProtocolType實(shí)例的初始化,拷貝,內(nèi)存消減和銷毀的。ValueWitnessTable在SIL中還可以拆分為%relative_vwtable和%absolute_vwtable,我們這里先不做展開(kāi)。ValueWitnessTable和ProtocolWitnessTable通過(guò)分工,去管理ProtocolType實(shí)例的內(nèi)存管理(初始化,拷貝,銷毀)和方法調(diào)用。我們來(lái)借助具體的示例進(jìn)行進(jìn)一步了解:在Swift編譯器中,通過(guò)ExistentialContainer實(shí)現(xiàn)的偽代碼如下:我們知道,Swift中Class的實(shí)例和屬性都存儲(chǔ)在堆區(qū),Struct實(shí)例在棧區(qū),如果包含指針屬性則存儲(chǔ)在堆區(qū),ProtocolType如何存儲(chǔ)屬性?SmallNumber通過(guò)ExistentialContainer內(nèi)聯(lián)實(shí)現(xiàn),大數(shù)存在堆區(qū)。如何處理Copy呢?在出現(xiàn)Copy情況時(shí):會(huì)將新的ExsitentialContainer的valueBuffer指向同一個(gè)value即創(chuàng)建指針引用,但是如果要改變值怎么辦?我們知道Struct值的修改和Class不同,Copy是不應(yīng)該影響原實(shí)例的值的。這里用到了一個(gè)技術(shù)叫做IndirectStorageWithCopy-On-Write,即優(yōu)先使用內(nèi)存指針。通過(guò)提高內(nèi)存指針的使用,來(lái)降低堆區(qū)內(nèi)存的初始化。降低內(nèi)存消耗。在需要修改值的時(shí)候,會(huì)先檢測(cè)引用計(jì)數(shù)檢測(cè),如果有大于1的引用計(jì)數(shù),則開(kāi)辟新內(nèi)存,創(chuàng)建新的實(shí)例。在對(duì)內(nèi)容進(jìn)行變更的時(shí)候,會(huì)開(kāi)啟一塊新的內(nèi)存,偽代碼如下:這樣實(shí)現(xiàn)的目的:通過(guò)多份指針去引用同一份地址的成本遠(yuǎn)遠(yuǎn)低于開(kāi)辟多份堆內(nèi)存。以下對(duì)比圖:支持ProtocolType的動(dòng)態(tài)多態(tài)(DynamicPolymorphism)行為。通過(guò)使用WitnessTable和ExistentialContainer來(lái)實(shí)現(xiàn)。對(duì)于大數(shù)的拷貝可以通過(guò)IndirectStorage間接存儲(chǔ)來(lái)進(jìn)行優(yōu)化。說(shuō)到動(dòng)態(tài)多態(tài)DynamicPolymorphism,我們就要問(wèn)了,什么是靜態(tài)多態(tài)StaticPolymorphism,看看下面示例:這種情況我們就可以用到泛型Genericcode來(lái)實(shí)現(xiàn),進(jìn)行進(jìn)一步優(yōu)化。我們接下來(lái)會(huì)討論泛型屬性的存儲(chǔ)方式和泛型方法是如何分派的。泛型和ProtocolType的區(qū)別在于:泛型支持的是靜態(tài)多態(tài)。每個(gè)調(diào)用上下文只有一種類型。查看下面的示例,foo和bar方法是同一種類型。在調(diào)用鏈中會(huì)通過(guò)類型降級(jí)進(jìn)行類型取代。對(duì)于以下示例:分析方法foo和bar的調(diào)用過(guò)程:泛型方法調(diào)用的具體實(shí)現(xiàn)為:同一種類型的任何實(shí)例,都共享同樣的實(shí)現(xiàn),即使用同一個(gè)ProtocolWitnessTable。使用Protocol/ValueWitnessTable。每個(gè)調(diào)用上下文只有一種類型:這里沒(méi)有使用ExistentialContainer,而是將Protocol/ValueWitnessTable作為調(diào)用方的額外參數(shù)進(jìn)行傳遞。變量初始化和方法調(diào)用,都使用傳入的VWT和PWT來(lái)執(zhí)行??吹竭@里,我們并不覺(jué)得泛型比ProtocolType有什么更快的特性,泛型如何更快呢?靜態(tài)多態(tài)前提下可以進(jìn)行進(jìn)一步的優(yōu)化,稱為特定泛型優(yōu)化。靜態(tài)多態(tài):在調(diào)用站中只有一種類型Swift使用只有一種類型的特點(diǎn),來(lái)進(jìn)行類型降級(jí)取代。類型降級(jí)后,產(chǎn)生特定類型的方法為泛型的每個(gè)類型創(chuàng)造對(duì)應(yīng)的方法這時(shí)候你可能會(huì)問(wèn),那每一種類型都產(chǎn)生一個(gè)新的方法,代碼空間豈不爆炸?靜態(tài)多態(tài)下進(jìn)行特定優(yōu)化specialization因?yàn)槭庆o態(tài)多態(tài)。所以可以進(jìn)行很強(qiáng)大的優(yōu)化,比如進(jìn)行內(nèi)聯(lián)實(shí)現(xiàn),并且通過(guò)獲取上下文來(lái)進(jìn)行更進(jìn)一步的優(yōu)化。從而降低方法數(shù)量。優(yōu)化后可以更精確和具體。例如:從普通的泛型展開(kāi)如下,因?yàn)橐С炙蓄愋偷膍in方法,所以需要對(duì)泛型類型進(jìn)行計(jì)算,包括初始化地址、內(nèi)存分配、生命周期管理等。除了對(duì)value的操作,還要對(duì)方法進(jìn)行操作。這是一個(gè)非常的的工程。在確定入?yún)㈩愋蜁r(shí),比如Int,編譯器可以通過(guò)泛型特化,進(jìn)行類型取代(TypeSubstitute),優(yōu)化為:泛型特化specilization是何時(shí)發(fā)生的?在使用特定優(yōu)化時(shí),調(diào)用方需要進(jìn)行類型推斷,這里需要知曉類型的上下文,例如類型的定義和內(nèi)部方法實(shí)現(xiàn)。如果調(diào)用方和類型是單獨(dú)編譯的,就無(wú)法在調(diào)用方推斷類型的內(nèi)部實(shí)行,就無(wú)法使用特定優(yōu)化,保證這些代碼一起進(jìn)行編譯,這里就用到了wholemoduleoptimization。而wholemoduleoptimization是對(duì)于調(diào)用方和被調(diào)用方的方法在不同文件時(shí),對(duì)其進(jìn)行泛型特化優(yōu)化的前提。特定泛型的進(jìn)一步優(yōu)化:在用到多種泛型,且確定泛型類型不會(huì)在運(yùn)行時(shí)修改時(shí),就可以對(duì)成對(duì)泛型的使用進(jìn)行進(jìn)一步優(yōu)化。優(yōu)化的方式是將泛型的內(nèi)存分配由指針指定,變?yōu)閮?nèi)存內(nèi)聯(lián),不再有額外的堆初始化消耗。請(qǐng)注意,因?yàn)檫M(jìn)行了存儲(chǔ)內(nèi)聯(lián),已經(jīng)確定了泛型特定類型的內(nèi)存分布,泛型的內(nèi)存內(nèi)聯(lián)不能存儲(chǔ)不同類型。所以再次強(qiáng)調(diào)此種優(yōu)化只適用于在運(yùn)行時(shí)不會(huì)修改泛型類型,即不能同時(shí)支持一個(gè)方法中包含line和point兩種類型。wholemoduleoptimization是用于Swift編譯器的優(yōu)化機(jī)制。可以通過(guò)-whole-module-optimization(或-wmo)進(jìn)行打開(kāi)。在XCode8之后默認(rèn)打開(kāi)。SwiftPackageManager在release模式默認(rèn)使用wholemoduleoptimization。module是多個(gè)文件集合。編譯器在對(duì)源文件進(jìn)行語(yǔ)法分析之后,會(huì)對(duì)其進(jìn)行優(yōu)化,生成機(jī)器碼并輸出目標(biāo)文件,之后鏈接器聯(lián)合所有的目標(biāo)文件生成共享庫(kù)或可執(zhí)行文件。wholemoduleoptimization通過(guò)跨函數(shù)優(yōu)化,可以進(jìn)行內(nèi)聯(lián)等優(yōu)化操作,對(duì)于泛型,可以通過(guò)獲取類型的具體實(shí)現(xiàn)來(lái)進(jìn)行推斷優(yōu)化,進(jìn)行類型降級(jí)方法內(nèi)聯(lián),刪除多余方法等操作。全模塊優(yōu)化的優(yōu)勢(shì)編譯器掌握所有方法的實(shí)現(xiàn),可以進(jìn)行內(nèi)聯(lián)和泛型特化等優(yōu)化,通過(guò)計(jì)算所有方法的引用,移除多余的引用計(jì)數(shù)操作。通過(guò)知曉所有的非公共方法,如果這寫方法沒(méi)有被使用,就可以對(duì)其進(jìn)行消除。如何降低編譯時(shí)間和全模塊優(yōu)化相反的是文件優(yōu)化,即對(duì)單個(gè)文件進(jìn)行編譯。這樣的好處在于可以并行執(zhí)行,并且對(duì)于沒(méi)有修改的文件不會(huì)再次編譯。缺點(diǎn)在于編譯器無(wú)法獲知全貌,無(wú)法進(jìn)行深度優(yōu)化,全模塊優(yōu)化如何避免沒(méi)修改的文件再次編譯。編譯器內(nèi)部運(yùn)行過(guò)程分為:語(yǔ)法分析,類型檢查,SIL優(yōu)化,LLVM后端處理。語(yǔ)法分析和類型檢查一般很快,SIL優(yōu)化執(zhí)行了重要的Swift特定優(yōu)化,例如泛型特化和方法內(nèi)聯(lián)等,該過(guò)程大概占用真?zhèn)€編譯時(shí)間的三分之一。LLVM后端執(zhí)行占用了大部分的編譯時(shí)間,用于運(yùn)行降級(jí)優(yōu)化和生成代碼。進(jìn)行全模塊優(yōu)化后,SIL優(yōu)化會(huì)將模塊再次拆分為多個(gè)部分,LLVM后端通過(guò)多線程對(duì)這些拆分模塊進(jìn)行處理,對(duì)于沒(méi)有修改的部分,不會(huì)進(jìn)行再處理。這樣就避免了修改一小部分,整個(gè)大模塊進(jìn)行LLVM后端執(zhí)行,并且多線程并行操作也會(huì)縮短處理時(shí)間。Swift因?yàn)榉椒ǚ峙蓹C(jī)制問(wèn)題,所以在設(shè)計(jì)和優(yōu)化后,會(huì)產(chǎn)生和我們常規(guī)理解不太一致的結(jié)果,這當(dāng)然不能算Bug。但是還是要單獨(dú)進(jìn)行說(shuō)明,避免在開(kāi)發(fā)過(guò)程中,因?yàn)閷?duì)機(jī)制的掌握不足,造成預(yù)期和執(zhí)行出入導(dǎo)致的問(wèn)題。Messagedispatch我們通過(guò)上面說(shuō)明結(jié)合StaticdispatchVSDynamicdispatch對(duì)方法分派方式有了了解。這里需要對(duì)Objective-C的方法分派方式進(jìn)行說(shuō)明。熟悉OC的人都知道,OC采用了運(yùn)行時(shí)機(jī)制使用obj_msgSend發(fā)送消息,runtime非常的靈活,我們不僅可以對(duì)方法調(diào)用采用swizzling,對(duì)于對(duì)象也可以通過(guò)isa-swizzling來(lái)擴(kuò)展功能,應(yīng)用場(chǎng)景有我們常用的hook和大家熟知的KVO。大家在使用Swift進(jìn)行開(kāi)發(fā)時(shí)都會(huì)問(wèn),Swift是否可以使用OC的運(yùn)行時(shí)和消息轉(zhuǎn)發(fā)機(jī)制呢?答案是可以。Swift可以通過(guò)關(guān)鍵字dynamic對(duì)方法進(jìn)行標(biāo)記,這樣就會(huì)告訴編譯器,此方法使用的是OC的運(yùn)行時(shí)機(jī)制。注意:我們常見(jiàn)的關(guān)鍵字@ObjC并不會(huì)改變Swift原有的方法分派機(jī)制,關(guān)鍵字@ObjC的作用只是告訴編譯器,該段代碼對(duì)于OC可見(jiàn)。注意:我們常見(jiàn)的關(guān)鍵字@ObjC并不會(huì)改變Swift原有的方法分派機(jī)制,關(guān)鍵字@ObjC的作用只是告訴編譯器,該段代碼對(duì)于OC可見(jiàn)??偨Y(jié)來(lái)說(shuō),Swift通過(guò)dynamic關(guān)鍵字的擴(kuò)展后,一共包含三種方法分派方式:Staticdispatch,Tabledispatch和Messagedispatch。下表為不同的數(shù)據(jù)結(jié)構(gòu)在不同情況下采取的分派方式:如果在開(kāi)發(fā)過(guò)程中,錯(cuò)誤的混合了這幾種分派方式,就可能出現(xiàn)Bug,以下我們對(duì)這些Bug進(jìn)行分析:SR-584此情況是在子類的extension中重載父類方法時(shí),出現(xiàn)和預(yù)期不同的行為。執(zhí)行以下代碼,直接調(diào)用沒(méi)有問(wèn)題:間接調(diào)用結(jié)果和預(yù)期不同:在Base.directProperty前添加dynamic關(guān)鍵字就可以獲得"thisisSub"的結(jié)果。Swift在extension文檔中說(shuō)明,不能在extension中重載已經(jīng)存在的方法?!癊xtensionscanaddnewfunctionalitytoatype,buttheycannotoverrideexistingfunctionality.”“Extensionscanaddnewfunctionalitytoatype,buttheycannotoverrideexistingfunctionality.”會(huì)出現(xiàn)警告:Cannotoverrideanon-dynamicclassdeclarationfromanextension。出現(xiàn)這個(gè)問(wèn)題的原因是,NSObject的extension是使用的Messagedispatch,而InitialDeclaration使用的是Tabledispath(查看上圖SwiftDispatchMethod)。extension重載的方法添加在了Messagedispatch內(nèi),沒(méi)有修改虛函數(shù)表,虛函數(shù)表內(nèi)還是父類的方法,故會(huì)執(zhí)行父類方法。想在extension重載方法,需要標(biāo)明dynamic來(lái)使用Messagedispatch。SR-103協(xié)議的擴(kuò)展內(nèi)實(shí)現(xiàn)的方法,無(wú)法被遵守類的子類重載:現(xiàn)在定義一個(gè)遵守了協(xié)議的類Person。遵守協(xié)議類的子類LoudPerson:執(zhí)行下面代碼結(jié)果為:不符合預(yù)期的代碼:注意,在子類LoudPerson中沒(méi)有出現(xiàn)override關(guān)鍵字。可以理解為L(zhǎng)oudPerson并沒(méi)有成功注冊(cè)Greetable在Witnesstable的方法。所以對(duì)于聲明為Person實(shí)際為L(zhǎng)oudPerson的實(shí)例,會(huì)在編譯器通過(guò)Person去查找,Person沒(méi)有實(shí)現(xiàn)協(xié)議方法,則不產(chǎn)生Witnesstable,sayHi方法是直接調(diào)用的。解決辦法是在base類內(nèi)實(shí)現(xiàn)協(xié)議方法,無(wú)需實(shí)現(xiàn)也要提供默認(rèn)方法?;蛘邔⒒悩?biāo)記為final來(lái)避免繼承。進(jìn)一步通過(guò)示例去理解:其他我們知道Classextension使用的是Staticdispatch:以上代碼會(huì)出現(xiàn)錯(cuò)誤,提示Declarationsinextensionsca

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論