1.可重用對象的使用
在iOS的一些視圖中,它們的內(nèi)部包含了子視圖,當父視圖顯示區(qū)域發(fā)生變化時(如用手滑動屏幕),原來在屏幕中的子視圖就會滑出到屏幕之外,而原來在屏幕之外的子視圖就有機會進入屏幕中。如圖1所示,當屏幕向上滑動時,Cupertino單元格滑出屏幕之外,Sherman Oaks單元格滑入到屏幕中。
圖1 表視圖中的可重用單元格
這些操作會有什么問題嗎?南昌網(wǎng)絡(luò)公司小編告訴你如果每次新單元格進入到屏幕中都去實例化一個新的單元格,必然增加內(nèi)存開銷。采用可重用對象設(shè)計可以不去實例化新的單元格,而是先使用可重用單元格標識到視圖中去找,如果找到則使用,沒有則創(chuàng)建。
在iOS 6之后,可以使用可重用對象的父視圖有表視圖、集合視圖(UICollectionView)和地圖視圖(MKMapView)。
1.1 表視圖中的可重用對象
在iOS 6之后,表視圖中有兩種子視圖采用可重用對象設(shè)計,它們是表視圖單元格(UITableViewCell)和表視圖節(jié)頭節(jié)腳(UITableViewHeaderFooterView)。
(1)表視圖單元格
表視圖單元格的重用方法有兩個:dequeueReusableCellWithIdentifier:方法和 dequeueReusableCellWithIdentifier:forIndexPath:方法。
通過dequeueReusableCellWithIdentifier:方法,可以用標識符從表視圖中獲得可重用單元格,模式代碼如下:
要在表視圖數(shù)據(jù)源的tableView:cellForRowAtIndexPath:方法中使用可重用單元格設(shè)計,首先通過dequeueReusableCellWithIdentifier:方法從表視圖中找,如果cell為空,則需要使用initWithStyle:reuseIdentifier:構(gòu)造器創(chuàng)建。
dequeueReusableCellWithIdentifier:forIndexPath:方法是iOS 6之后提供的方法。與上一個方法相比,該方法的簽名多了forIndexPath:部分。它可以通過指定單元格位置獲得可重用單元格,不需要判斷,模式代碼如下:
這個方法的使用有一些限制,它只能應(yīng)用于iOS故事板中,并且在故事板中設(shè)計表視圖單元格后,指定表視圖單元格為動態(tài)的,Identifier屬性設(shè)置為cellIdentifier。圖2設(shè)定了表視圖單元格的屬性。
圖2 設(shè)定表視圖單元格的屬性
(2)UITableViewHeaderFooterView也是iOS 6之后新加的內(nèi)容,節(jié)頭和節(jié)腳也會反復(fù)出現(xiàn),它也需要可重用設(shè)計。使用表視圖的dequeueReusableHeaderFooterViewWithIdentifier:方法獲得UITableViewHeaderFooterView對象后,如果沒有可重用的UITableViewHeaderFooterView對象,則使用initWithReuseIdentifier:構(gòu)造器創(chuàng)建。其模式代碼如下:
需要在表視圖委托協(xié)議UITableViewDelegate中的tableView:viewForHeaderInSection:方法中使用可重用對象設(shè)計。
1.2 集合視圖中的可重用對象
集合視圖在iOS 6之后才可以使用。它也有兩種子視圖采用可重用對象設(shè)計,它們是單元格視圖和補充視圖,這兩個視圖都繼承自UICollectionReusableView,使用時需要自己編寫相關(guān)代碼。
(1)單元格視圖
在集合視圖中,我們可以使用UICollectionView的dequeueReusableCellWithReuseIdentifier:forIndexPath:方法獲得可重用的單元格,模式代碼如下:
在上述代碼中,collectionView:cellForItemAtIndexPath:方法是集合視圖的數(shù)據(jù)源方法,其中Cell是我們自定義的繼承自UICollectionReusableView的單元格類。使用dequeueReusableCellWithReuseIdentifier:時,需要使用故事板設(shè)計UI,并且需要將單元格的Identifier屬性設(shè)置為Cell(如圖3所示)。
圖3 設(shè)定集合視圖單元格的屬性
(2)補充視圖
集合視圖單元格可以使用UICollectionView的dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:方法獲得可重用的補充視圖,模式代碼如下:
collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法是集合視圖的數(shù)據(jù)源方法,其中HeaderView是我們自定義的繼承自UICollectionReusableView的補充視圖類。使用dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:時,需要使用故事板設(shè)計UI,并將補充視圖的Identifier屬性設(shè)置為HeaderIdentifier,如圖4所示。
圖4 設(shè)定補充視圖的屬性
1.3 地圖視圖中的可重用對象
在開發(fā)地圖應(yīng)用時,也有一個可重用對MKPinAnnotationView,它是在地圖上的一個標注。使用地圖視圖的
dequeueReusableAnnotationViewWithIdentifier:方法,可以獲得MKPinAnnotationView對象。如果沒有可重用的MKPinAnnotationView對象,則使用initWithAnnotation:reuseIdentifier:構(gòu)造器創(chuàng)建。其模式代碼如下:
這段處理代碼是地圖視圖中常用的處理方式,請大家牢記。
2.并發(fā)處理與多核 CPU
并發(fā)處理能夠同時處理多個任務(wù)。在CPU單核時代,可以使用多線程技術(shù)進行并發(fā)處理。現(xiàn)在,iOS設(shè)備的CPU已經(jīng)進入多核時代,從iPhone 4S和iPad 2之后開始采用A5雙核CPU設(shè)計。異步設(shè)計方法可以充分地發(fā)揮多核優(yōu)勢。GCD(Grand Central Dispatch)是一種異步方法,是專為多核CPU而設(shè)計的并發(fā)處理技術(shù)。
本節(jié)中,南昌網(wǎng)絡(luò)公司小編就和大家一起來學(xué)習(xí)主線程阻塞問題以及GCD的相關(guān)內(nèi)容。
2.1 主線程阻塞問題
主線程所做的事情應(yīng)該是響應(yīng)用戶輸入、事件處理、更新UI,而耗時的任務(wù)不要在主線程中處理。由于耗時任務(wù)使得主線程被阻塞了,不能響應(yīng)用戶的請求,這樣應(yīng)用的用戶體驗會很差。
下面我們先看一個例子。如圖5所示,點擊Load Image按鈕,會從http://www.51work6.com/book/test2.jpg中加載圖片。當我們點擊Load Image按鈕時,按鈕會一直處于按下狀態(tài)而不彈起,直到圖片顯示“完成”。這是因為主線程要進行耗時的處理(如進行網(wǎng)絡(luò)通信、數(shù)據(jù)傳輸?shù)热蝿?wù)),導(dǎo)致主線程不能響應(yīng)用戶的輸入和請求,這就是我們要討論的線程阻塞問題。
圖5 主線程阻塞案例
下面我們看看代碼部分。在BlockDemo工程中,ViewController中click:方法的代碼如下:
由于不能直接通過URL創(chuàng)建UIImage對象,因此先構(gòu)建NSData對象,它是從URL請求回來的二進制數(shù)據(jù)對象,然后再用它來構(gòu)建UIImage對象。最后,把UIImage對象賦值給UIImageView的image屬性。
那么,如何解決主線程阻塞問題呢?那就是把這些執(zhí)行比較耗時的阻塞線程的任務(wù)從主線程中移出到其他線程中處理。
2.2 選擇 NSThread 還是 GCD
解決主線程阻塞問題時,我們可以使用多線程。NSThread是多線程類,但是麻煩的是我們需要管理線程,包括創(chuàng)建線程、線程間通信和銷毀線程等。
GCD(Grand Central Dispatch)是基于C語句級別的API,它提供了C函數(shù)。GCD代碼編寫簡單,還支持多核CPU處理。GCD是蘋果重點推薦的并發(fā)技術(shù),唯一的缺陷是它是基于C語言的API。
在GCD中,有一個重要的概念,那就是派發(fā)隊列(dispatch queue)。派發(fā)隊列是一個對象,它可以接受任務(wù),并將任務(wù)以先到先執(zhí)行的順序來執(zhí)行。派發(fā)隊列可以是并發(fā)的或串行的。并發(fā)隊列可以執(zhí)行多任務(wù),串行隊列同一時間只執(zhí)行單一任務(wù)。在GCD中,有3種類型的派發(fā)隊列。
串行隊列。串行隊列通常用于同步訪問一個特定的資源,每次只能執(zhí)行一個任務(wù)。使用函數(shù)dispatch_queue_create,可以創(chuàng)建串行隊列。
并發(fā)隊列。也稱為全局派發(fā)隊列,可以并發(fā)地執(zhí)行一個或多個任務(wù)。并發(fā)隊列分為高、中、低3個優(yōu)先級,中級為默認級別??梢哉{(diào)用dispatch_get_global_queue函數(shù)設(shè)定優(yōu)先級來訪問隊列。dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)語句用于獲得并發(fā)隊列對象,其中DISPATCH_QUEUE_PRIORITY_DEFAULT是默認的優(yōu)先級常量。
主隊列。它在應(yīng)用程序的主線程中,用于更新UI。其他的兩個隊列不能更新UI。使用dispatch_get_main_queue函數(shù),可以獲得主隊列。
我們把BlockDemo工程修改為GCD實現(xiàn),具體代碼如下:
在上述代碼中,dispatch_async函數(shù)用于異步執(zhí)行任務(wù),但是它在串行隊列中仍然是同步執(zhí)行的。在更新UI時,如self.imageView.image = img語句,dispatch_async函數(shù)必須在主線程中執(zhí)行。我們使用第①行代碼在主隊列中更新UI。
通過近幾天的學(xué)習(xí),我們了解了性能優(yōu)化方法,其中包括內(nèi)存優(yōu)化、資源文件優(yōu)化、延遲加載、持久化優(yōu)化、使用可重用對象和并發(fā)訪問等。這些內(nèi)容都是非常重要的,希望對大家有所幫助。了解更多相關(guān)資訊,關(guān)注南昌網(wǎng)絡(luò)公司--百恒網(wǎng)絡(luò)官方網(wǎng)站。百恒網(wǎng)絡(luò)是一家專業(yè)從事南昌網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、網(wǎng)絡(luò)營銷等服務(wù)的南昌網(wǎng)絡(luò)公司,技術(shù)過硬,經(jīng)驗豐富。如有任何網(wǎng)站方面的問題,百恒網(wǎng)絡(luò)隨時歡迎大家來電咨詢,我們專業(yè)為您解答!