iOS面試題手記(2)

1.一個(gè)objc對象的isa的指針指向什么?有什么作用?

指向他的類對象,從而可以找到對象上的方法

2.一個(gè) NSObject 對象占用多少內(nèi)存空間?

*一個(gè)NSObject對象占用的大小其實(shí)就是一個(gè)isa指針的大小。在64bit是8字節(jié)。 但是!!系統(tǒng)* *真正分配內(nèi)存的時(shí)候是分配了16字節(jié)!*

3.說一下對 class_rw_t 的理解?

rw代表可讀可寫,class_rw_t 中保存了Objc類的屬性,方法,遵循的協(xié)議等信息

// 可讀可寫

struct class_rw_t {

// Be warned that Symbolication knows the layout of this structure.

uint32_t flags;

uint32_t version;

const class_ro_t *ro; // 指向只讀的結(jié)構(gòu)體,存放類初始信息

/*

這三個(gè)都是二位數(shù)組,是可讀可寫的,包含了類的初始內(nèi)容、分類的內(nèi)容。

methods中,存儲(chǔ) method_list_t ----> method_t

二維數(shù)組,method_list_t --> method_t

這三個(gè)二位數(shù)組中的數(shù)據(jù)有一部分是從class_ro_t中合并過來的。

*/

method_array_t methods; // 方法列表(類對象存放對象方法,元類對象存放類方法)

property_array_t properties; // 屬性列表

protocol_array_t protocols; //協(xié)議列表

Class firstSubclass;

Class nextSiblingClass;

//...

}

3.說一下對 class_ro_t 的理解?

存儲(chǔ)了當(dāng)前類在編譯器就已經(jīng)確定的屬性,方法以及遵循的協(xié)議

struct class_ro_t {

    uint32_t flags;

    uint32_t instanceStart;

    uint32_t instanceSize;

    uint32_t reserved;

    const uint8_t * ivarLayout;

    const char * name;

    method_list_t * baseMethodList;

    protocol_list_t * baseProtocols;

    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;

    property_list_t *baseProperties;

};

4.說一下對 isa 指針的理解, 對象的isa 指針指向哪里?isa 指針有哪兩種類型?

isa等價(jià)于is kind of,*實(shí)例對象isa指向類對象,類對象isa指向元類對象,元類對象isa指向元類的基類。

isa有兩種,1*純指針,指向內(nèi)存地址 2**NON_POINTER_ISA,除了內(nèi)存地址,還存有一些其他信息

5.實(shí)例對象的數(shù)據(jù)結(jié)構(gòu)?

本質(zhì)上objc_object的私有屬性只有一個(gè)isa指針,指向類對象的內(nèi)存地址

6.什么是method swizzling(俗稱黑魔法)

簡單來說就是方法交換,每個(gè)類都有一個(gè)方法列表,存著方法名字和實(shí)現(xiàn)的映射關(guān)系,selector的本質(zhì)其實(shí)就是方法名,IMP有點(diǎn)類似函數(shù)指針,指向具體的Method實(shí)現(xiàn),通過selector就可以找到對應(yīng)的IMP。換方法的幾種方式利用 method_exchangeImplementations 交換兩個(gè)方法的實(shí)現(xiàn),利用 class_replaceMethod替換方法的實(shí)現(xiàn),利用 method_setImplementation 來直接設(shè)置某個(gè)方法的IMP

7.什么時(shí)候會(huì)報(bào)unrecognized selector的異常?

objc在向一個(gè)對象發(fā)送消息時(shí),runtime庫會(huì)根據(jù)isa指針找到該對象實(shí)際所屬的類,然后再該類的方法列表及父類方法列表中尋找方法運(yùn)行,如果在最頂層父類依然找不到對應(yīng)方法,會(huì)進(jìn)入消息轉(zhuǎn)發(fā)階段,如果消息三次轉(zhuǎn)發(fā)流程任然未實(shí)現(xiàn),程序會(huì)拋出這個(gè)異常。

8.如何給 Category 添加屬性?關(guān)聯(lián)對象以什么形式進(jìn)行存儲(chǔ)?

關(guān)聯(lián)對象以哈希表的格式,存儲(chǔ)在一個(gè)全局的單例中

9.能否向編譯后得到的類中增加實(shí)例變量?能否向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量?為什么?

不能向編譯后得到的類中添加實(shí)例變量,能向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量

1.因?yàn)榫幾g后的類已經(jīng)注冊在runtime中,類結(jié)構(gòu)體中的實(shí)例變量離岸邊和內(nèi)存大小已確定,同時(shí)runtime會(huì)調(diào)用class_setvarlayout 或 class_setWeaklvarLayout 來處理strong weak 引用,所以不能添加

2.運(yùn)行時(shí)創(chuàng)建的類是可以添加實(shí)例變量,調(diào)用class_addIvar函數(shù). 但是的在調(diào)用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上.

10.類對象的數(shù)據(jù)結(jié)構(gòu)?

類對象就是objc_class,是一個(gè)繼承自objc_object結(jié)構(gòu)體,所以包含isa指針

isa:指向元類

superClass:指向父類

Cache:方法的緩存列表

data:數(shù)據(jù),是一個(gè)被封裝好的class_rw_t

structobjc_class:objc_object{// Class ISA;Class superclass;//父類指針cache_t cache;// formerly cache pointer and vtable 方法緩存class_data_bits_t bits;// class_rw_t * plus custom rr/alloc flags 用于獲取地址class_rw_t*data(){returnbits.data();// &FAST_DATA_MASK 獲取地址值}

11.runtime如何通過selector找到對應(yīng)的IMP地址?

每個(gè)類對象都有一個(gè)方法列表,方法列表中記錄著方法的名稱,實(shí)現(xiàn)一鍵參數(shù)類型,通過方法名稱就可以在列表中找出對應(yīng)的方法實(shí)現(xiàn)

12.objc中向一個(gè)nil對象發(fā)送消息將會(huì)發(fā)生什么?

向一個(gè)nil對象發(fā)送消息,在尋找對象的isa指針的時(shí)候就0地址返回了,不會(huì)出現(xiàn)任何錯(cuò)誤

詳解:

如果一個(gè)方法返回值是一個(gè)對象,那么發(fā)送給nil的消息將返回0(nil);

如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*) ,float,double,long double 或者long long的整型標(biāo)量,發(fā)送給nil的消息將返回0;

如果方法返回值為結(jié)構(gòu)體,發(fā)送給nil的消息將返回0。結(jié)構(gòu)體中各個(gè)字段的值將都是0;

如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給nil的消息的返回值將是未定義的。

13.objc在向一個(gè)對象發(fā)送消息時(shí),發(fā)生了什么?

runtime會(huì)根據(jù)對象的isa指針找到該對象所屬的類,然后再方法列表以及父類方法列表中尋找方法實(shí)現(xiàn),如果一直到根類還沒找到,轉(zhuǎn)向攔截調(diào)用,走消息轉(zhuǎn)發(fā)機(jī)制,一旦找到,就去執(zhí)行他的IMP

14.isKindOfClass 與 isMemberOfClass

isKindOfClass 是確定一個(gè)對象是否是一個(gè)類的成員,或者是派生字該類

isMemberOfClass確定一個(gè)對象是否是當(dāng)前類的成員

15.Category 在編譯過后,是在什么時(shí)機(jī)與原有的類合并到一起的?

1.程序啟動(dòng)后,通過編譯后,runtime初始化,調(diào)用_objc_init

2.然后會(huì)map_images

3.接下來調(diào)用map_images_nolock

4.然后read_images,讀取所有的類的相關(guān)信息

5.最后調(diào)用reMethodizeClass,進(jìn)行重新方法化

6.在reMethodizeClass內(nèi)部會(huì)調(diào)用attachCategorise,這個(gè)方法會(huì)傳入Class和Category,講方法和協(xié)議列表與原有的類合并,最后加入到class_rw_t結(jié)構(gòu)體中

16.Category 有哪些用途?

給系統(tǒng)類添加方法和屬性(需要關(guān)聯(lián)對象),對某個(gè)類大量方法,可以實(shí)現(xiàn)按照不同的名稱歸類

17.為什么 NSTimer 有時(shí)候不好使?

  因?yàn)閯?chuàng)建的NSTimer默認(rèn)被加入到defaultMode,當(dāng)Runloop的Mode變化時(shí),當(dāng)前timer不工作

18.RunLoop的Mode有幾種?
當(dāng)RunLoop在Mode1上時(shí),是無法接受Mode2或Mode3上的Source,Timer,Observer事件的
總共有五種CFRunLoopMode:
KCFRunLoopDefaultMode:默認(rèn)模式,主線程就是在這個(gè)模式下運(yùn)行
UITrackingRunLoopMode:跟蹤用戶交事件(用于ScrollView追蹤滑動(dòng))
UIInitiazationRunLoopMode:剛啟動(dòng)App時(shí)進(jìn)入的第一個(gè)Mode,啟動(dòng)完成后不再使用
GSEventReiviceRunLoopMode:接受系統(tǒng)內(nèi)部事件,通常用不到
KCFRunLoopCommonModes:偽模式,不是一種真正的運(yùn)行模式,是同步Source/Timer?Observer到多個(gè)Mode的一種解決方案

19.RunLoop與NSTimer
一個(gè)比較常見的問題:滑動(dòng)tableView時(shí),定時(shí)器還會(huì)生效嗎?
默認(rèn)情況下RunLoop運(yùn)行在kCFRunLoopDefaultMode下,而當(dāng)滑動(dòng)tableView時(shí),RunLoop切換到UITrackingRunLoopMode,而Timer是在kCFRunLoopDefaultMode下的,就無法接受處理Timer的事件。
怎么去解決這個(gè)問題呢?把Timer添加到UITrackingRunLoopMode上并不能解決問題,因?yàn)檫@樣在默認(rèn)情況下就無法接受定時(shí)器事件了。
所以我們需要把Timer同時(shí)添加到UITrackingRunLoopMode和kCFRunLoopDefaultMode上。
那么如何把timer同時(shí)添加到多個(gè)mode上呢?就要用到NSRunLoopCommonModes了

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

Timer就被添加到多個(gè)mode上,這樣即使RunLoop由kCFRunLoopDefaultMode切換到UITrackingRunLoopMode下,也不會(huì)影響接收Timer事件

20.AFNetworking 中如何運(yùn)用 Runloop?

AFURLConnectionOperation 這個(gè)類是基于 NSURLConnection 構(gòu)建的,其希望能在后臺(tái)線程接收 Delegate 回調(diào)。為此 AFNetworking 單獨(dú)創(chuàng)建了一個(gè)線程,并在這個(gè)線程中啟動(dòng)了一個(gè) RunLoop.
RunLoop 啟動(dòng)前內(nèi)部必須要有至少一個(gè) Timer/Observer/Source,所以 AFNetworking 在 [runLoop run] 之前先創(chuàng)建了一個(gè)新的 NSMachPort 添加進(jìn)去了。通常情況下,調(diào)用者需要持有這個(gè) NSMachPort (mach_port) 并在外部線程通過這個(gè) port 發(fā)送消息到 loop 內(nèi);但此處添加 port 只是為了讓 RunLoop 不至于退出,并沒有用于實(shí)際的發(fā)送消息。

21.PerformSelector 的實(shí)現(xiàn)原理?
當(dāng)調(diào)用 NSObject 的 performSelecter:afterDelay: 或performSelector:onThread:后,實(shí)際內(nèi)部會(huì)創(chuàng)建一個(gè)Timer并添加到當(dāng)前線程的RunLoop中,如果當(dāng)前線程沒有RunLoop,方法會(huì)失效。
22.PerformSelector:afterDelay:這個(gè)方法在子線程中是否起作用?為什么?怎么解決?
不起作用,子線程默認(rèn)沒有RunLoop,也就沒有Timer,辦法是使用GCD來實(shí)現(xiàn):
Dispath_after

23.RunLoop和線程
線程和RunLoop是意義對應(yīng)的,隱射關(guān)系保存在一個(gè)全局字典中
自己創(chuàng)建的線程默認(rèn)是不開啟RunLoop的
1、怎么創(chuàng)建一個(gè)常駐線程?
1.為當(dāng)前線程開啟一個(gè)RunLoop(第一次調(diào)用 [NSRunLoop currentRunLoop]方法時(shí)實(shí)際是會(huì)先去創(chuàng)建一個(gè)RunLoop)
2.向RunLoop中添加一個(gè)維持RunLoop的時(shí)間循環(huán)(如果RunLoop的mode中一個(gè)item都沒有,RunLoop會(huì)退出)
3.啟動(dòng)RunLoop

  @autoreleasepool {
        
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        
        [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        
        [runLoop run];
        
    }

2.怎樣保證子線程數(shù)據(jù)回來更新UI的時(shí)候不打斷用戶的滑動(dòng)操作?
我們就可以將更新UI事件放在主線程的NSDefaultRunLoopMode上執(zhí)行即可,這樣就會(huì)等用戶不再滑動(dòng)頁面,主線程RunLoop由UITrackingRunLoopMode切換到NSDefaultRunLoopMode時(shí)再去更新UI

[self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO modes:@[NSDefaultRunLoopMode]];

24.RunLoop的數(shù)據(jù)結(jié)構(gòu)
RunLoop設(shè)計(jì)五個(gè)類:
CFRunLoop:RunLoop對象
CFRunLoopMode:運(yùn)行模式
CFRunLoopSource:輸入源/事件源
CFRunLoopTimer:定時(shí)源
CFRunLoopObserver:觀察者
1、CFRunLoop

由pthread(線程對象,說明RunLoop和線程是一一對應(yīng)的)、currentMode(當(dāng)前所處的運(yùn)行模式)、modes(多個(gè)運(yùn)行模式的集合)、commonModes(模式名稱字符串集合)、commonModelItems(Observer,Timer,Source集合)構(gòu)成

2、CFRunLoopMode

由name、source0、source1、observers、timers構(gòu)成

3、CFRunLoopSource

分為source0和source1兩種

source0:
即非基于port的,也就是用戶觸發(fā)的事件。需要手動(dòng)喚醒線程,將當(dāng)前線程從內(nèi)核態(tài)切換到用戶態(tài)
source1:
基于port的,包含一個(gè) mach_port 和一個(gè)回調(diào),可監(jiān)聽系統(tǒng)端口和通過內(nèi)核和其他線程發(fā)送的消息,能主動(dòng)喚醒RunLoop,接收分發(fā)系統(tǒng)事件。
具備喚醒線程的能力
4、CFRunLoopTimer

基于時(shí)間的觸發(fā)器,基本上說的就是NSTimer。在預(yù)設(shè)的時(shí)間點(diǎn)喚醒RunLoop執(zhí)行回調(diào)。因?yàn)樗腔赗unLoop的,因此它不是實(shí)時(shí)的(就是NSTimer 是不準(zhǔn)確的。 因?yàn)镽unLoop只負(fù)責(zé)分發(fā)源的消息。如果線程當(dāng)前正在處理繁重的任務(wù),就有可能導(dǎo)致Timer本次延時(shí),或者少執(zhí)行一次)。

5、CFRunLoopObserver

監(jiān)聽以下時(shí)間點(diǎn):CFRunLoopActivity

kCFRunLoopEntry
RunLoop準(zhǔn)備啟動(dòng)

kCFRunLoopBeforeTimers
RunLoop將要處理一些Timer相關(guān)事件

kCFRunLoopBeforeSources
RunLoop將要處理一些Source事件

kCFRunLoopBeforeWaiting
RunLoop將要進(jìn)行休眠狀態(tài),即將由用戶態(tài)切換到內(nèi)核態(tài)

kCFRunLoopAfterWaiting
RunLoop被喚醒,即從內(nèi)核態(tài)切換到用戶態(tài)后

kCFRunLoopExit
RunLoop退出

kCFRunLoopAllActivities
監(jiān)聽所有狀態(tài)

25.RunLoop概念
RunLoop是通過維護(hù)內(nèi)部的時(shí)間循環(huán)來對事件/消息進(jìn)行管理的一個(gè)對象
1.沒有消息時(shí),休眠避免占用資源,有用戶態(tài)切換到內(nèi)核態(tài)
2.有消息處理,由內(nèi)核態(tài)切換到用戶態(tài)
為什么main函數(shù)不會(huì)退出?
UIApplicationMain內(nèi)部默認(rèn)開啟了主線程的RunLoop,并執(zhí)行了一段無限循環(huán)的代 碼(不是簡單的for循環(huán)或while循環(huán))

26.解釋一下 NSTimer
NSTimer 其實(shí)就是 CFRunLoopTimerRef,他們之間是 toll-free bridged 的。一個(gè) NSTimer 注冊到 RunLoop 后,RunLoop 會(huì)為其重復(fù)的時(shí)間點(diǎn)注冊好事件。例如 10:00, 10:10, 10:20 這幾個(gè)時(shí)間點(diǎn)。RunLoop 為了節(jié)省資源,并不會(huì)在非常準(zhǔn)確的時(shí)間點(diǎn)回調(diào)這個(gè)Timer。Timer 有個(gè)屬性叫做 Tolerance (寬容度),標(biāo)示了當(dāng)時(shí)間點(diǎn)到后,容許有多少最大誤差。

27.什么是異步繪制?
就是可以在子線程把需要繪制的圖形,提前在子線程處理好,講準(zhǔn)備好的圖像數(shù)據(jù)直接返回給主線程使用,降低主線程的壓力。
異步繪制過程:
通過系統(tǒng)的[view.delegate displayLayer:]入口實(shí)現(xiàn)異步繪制
*代理負(fù)責(zé)生成對應(yīng)的 Bitmap
*設(shè)置該 Bitmap 為 layer.contents 屬性的值。
28.利用 runloop 解釋一下頁面的渲染的過程?
當(dāng)我們調(diào)用 [UIView setNeedsDisplay] 時(shí),這時(shí)會(huì)調(diào)用當(dāng)前 View.layer 的 [view.layer setNeedsDisplay]方法。

這等于給當(dāng)前的 layer 打上了一個(gè)臟標(biāo)記,而此時(shí)并沒有直接進(jìn)行繪制工作。而是會(huì)到當(dāng)前的 Runloop 即將休眠,也就是 beforeWaiting 時(shí)才會(huì)進(jìn)行繪制工作。

緊接著會(huì)調(diào)用 [CALayer display],進(jìn)入到真正繪制的工作。CALayer 層會(huì)判斷自己的 delegate 有沒有實(shí)現(xiàn)異步繪制的代理方法 displayer:,這個(gè)代理方法是異步繪制的入口,如果沒有實(shí)現(xiàn)這個(gè)方法,那么會(huì)繼續(xù)進(jìn)行系統(tǒng)繪制的流程,然后繪制結(jié)束。

CALayer 內(nèi)部會(huì)創(chuàng)建一個(gè) Backing Store,用來獲取圖形上下文。接下來會(huì)判斷這個(gè) layer 是否有 delegate。

如果有的話,會(huì)調(diào)用 [layer.delegate drawLayer:inContext:],并且會(huì)返回給我們 [UIView DrawRect:] 的回調(diào),讓我們在系統(tǒng)繪制的基礎(chǔ)之上再做一些事情。

如果沒有 delegate,那么會(huì)調(diào)用 [CALayer drawInContext:]。

以上兩個(gè)分支,最終 CALayer 都會(huì)將位圖提交到 Backing Store,最后提交給 GPU。

至此繪制的過程結(jié)束。

29.KVO (Key-value observing)
KVO就是觀察者模式的另一實(shí)現(xiàn),使用了isa混寫(isa-swizzling)來實(shí)現(xiàn)KVO
使用setter方法改變值KVO會(huì)生效,使用setValue:forKey即KVC改變值KVO也會(huì)生效,因?yàn)镵VC會(huì)去調(diào)用setter方法
通過賦值成員變量不會(huì)觸發(fā)KVO,因?yàn)闆]有調(diào)用setter方法,需要加上willChangeValueForKey和didChangeValueForKey方法來手動(dòng)觸發(fā)才行

30.KVC(Key-value coding)

KVO可以允許開發(fā)者通過Key名直接訪問對象屬性或者給屬性賦值,而不需要調(diào)用存取方法。這樣就可以在運(yùn)行時(shí)動(dòng)態(tài)的訪問和修改對象屬性,而不是在編譯時(shí)確定。

31.分類、擴(kuò)展、代理
一、分類
1.分類作用?
聲明私有方法,分解體積大的類文件,把framework的私有方法公開
2.分類特點(diǎn)
運(yùn)行時(shí)決定,可以為系統(tǒng)類添加分類

32.請說一下對 CALayer 的認(rèn)識(shí)
layer是圖層繪制,渲染,以及動(dòng)畫的完成者,無法處理觸摸事件,layer常見的屬性有Frame、Bounds、Position、AnchorPoint、Contents 等等。

33.Block的幾種形式
分為全局Block,堆Block,棧Block三種,其中棧Block存儲(chǔ)在棧(stack)區(qū),堆Block存儲(chǔ)在堆(heap)區(qū),全局Block存儲(chǔ)在已初始化數(shù)據(jù)(.data)區(qū)

34.什么是Block?
Block是將函數(shù)及其執(zhí)行上下文封裝起來的對象。block內(nèi)部有isa指針,所以說其本質(zhì)也是OC對象

35.iOS 性能優(yōu)化面試題
在性能優(yōu)化中一個(gè)最具參考價(jià)值的屬性是FPS:Frames Per Second,其實(shí)就是屏幕刷新率,蘋果的iphone推薦的刷新率是60Hz,F(xiàn)PS值的大小體現(xiàn)了頁面的流暢程度高低,當(dāng)?shù)陀?5的時(shí)候卡頓會(huì)比較明顯。
一.入門級(jí)
1.用ARC管理內(nèi)存
2、在正確的地方使用 reuseIdentifier
3.盡量把views設(shè)置成透明
4.避免過大的XIB
5.不要阻塞主線程
6.在ImageViews中調(diào)整圖片大小,最好保證圖片大小和imageView大小一致,縮放圖片會(huì)耗費(fèi)資源,可以在下載完成后用backgroundthread,縮放一次,然后在UIImageView中使用縮放后的圖片。
7.正確使用Collection
8.打開gzip壓縮
二.中級(jí)
1.重用和延遲加載(lazy load) Views
2.Cache
緩存那些不大可能經(jīng)常改變但需要讀取的東西,一些選項(xiàng)是,遠(yuǎn)端服務(wù)器的響應(yīng),圖片,甚至計(jì)算結(jié)果,比如UITableView的行高。
3.權(quán)衡渲染方法.性能能還是要bundle保持合適的大小。
4.處理內(nèi)存警告,移除對緩存,圖片object和其他一些重創(chuàng)建的objects的strongreference
5.重用大開銷對象
6.一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。然而,你又不可避免地需要使用它們,比如從JSON或者XML中解析數(shù)據(jù)。想要避免使用這個(gè)對象的瓶頸你就需要重用他們,可以通過添加屬性到你的class里或者創(chuàng)建靜態(tài)變量來實(shí)現(xiàn)。
7.避免反復(fù)處理數(shù)據(jù)庫,在服務(wù)端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)
8.選擇正確的數(shù)據(jù)格式
9.正確設(shè)定背景圖片
10.減少使用Web特性,盡可能的移除不必要的js,避免使用過大的框架,盡可能的異步記載不影響頁面表達(dá)的js
11.、Shadow Path 。CoreAnimation不得不先在后臺(tái)得出你的圖形并加好陰影然后才渲染,這開銷是很大的。使用shadowPath的話就避免了這個(gè)問題。使用shadow path的話iOS就不必每次都計(jì)算如何渲染,它使用一個(gè)預(yù)先計(jì)算好的路徑。
12.優(yōu)化tableview
正確使用reuseIdentifier來重用cells
盡量使所有的view opaque,包括cell自身
避免漸變,圖片縮放,后臺(tái)選人
緩存行高
如果cell內(nèi)現(xiàn)實(shí)的內(nèi)容來自web,使用異步加載,緩存請求結(jié)果
使用shadowPath來畫陰影
減少subviews的數(shù)量
盡量不適用cellForRowAtIndexPath:,如果你需要用到它,只用-一次然后緩存結(jié)果
使用正確的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù)
使用rowHeight, sectionFooterHeight 和 sectionHeaderHeight來設(shè)定固定的高,不要請求delegate
13、選擇正確的數(shù)據(jù)存儲(chǔ)選項(xiàng)
三、高級(jí)
1.加速啟動(dòng)時(shí)間,盡可能多的異步任務(wù),編碼龐大的XIB
2.使用Autorelease Pool
3.選擇是否緩存圖片
4.避免日期格式轉(zhuǎn)化
平時(shí)你是如何對代碼進(jìn)行性能優(yōu)化的?

利用性能分析工具檢測,包括靜態(tài) Analyze 工具,以及運(yùn)行時(shí) Profile 工具,通過Xcode工具欄中Product->Profile可以啟動(dòng),

比如測試程序啟動(dòng)運(yùn)行時(shí)間,當(dāng)點(diǎn)擊Time Profiler應(yīng)用程序開始運(yùn)行后.就能獲取到整個(gè)應(yīng)用程序運(yùn)行消耗時(shí)間分布和百分比.為了保證數(shù)據(jù)分析在統(tǒng)一使用場景真實(shí)需要注意一定要使用真機(jī),因?yàn)榇藭r(shí)模擬器是運(yùn)行在Mac上,而Mac上的CPU往往比iOS設(shè)備要快。

為了防止一個(gè)應(yīng)用占用過多的系統(tǒng)資源,開發(fā)iOS的蘋果工程師門設(shè)計(jì)了一個(gè)“看門狗”的機(jī)制。在不同的場景下,“看門狗”會(huì)監(jiān)測應(yīng)用的性能。如果超出了該場景所規(guī)定的運(yùn)行時(shí)間,“看門狗”就會(huì)強(qiáng)制終結(jié)這個(gè)應(yīng)用的進(jìn)程。開發(fā)者們在crashlog里面,會(huì)看到諸如0x8badf00d這樣的錯(cuò)誤代碼。

36.光柵化
光柵化是將幾何數(shù)據(jù)經(jīng)過一系列變化后最終轉(zhuǎn)換成像素,從而呈現(xiàn)在顯示設(shè)備的過程,本質(zhì)是坐標(biāo)變化和幾何離散化。
當(dāng)UItableview和UICollectionView的cell樣式一樣是,可以使用這個(gè)屬性提高性能

cell.layer.shouldRasterize=YES;

cell.layer.rasterizationScale=[[UIScreenmainScreen]scale];


37.日常如何檢查內(nèi)存泄露?
目前我知道的方式有以下幾種:
Memory Leaks
Alloctions
Analyse
Debug Memory Graph
MLeaksFinder
泄露的內(nèi)存主要有一下兩種:
1.Laek Memory 忘記Relase操作所泄露的內(nèi)存
2.Abandon Memory 循環(huán)引用,無法釋放掉的內(nèi)存
38.如何高性能的畫一個(gè)圓角?

視圖和圓角的大小對幀率并沒有什么卵影響,數(shù)量才是傷害的核心輸出
label.layer.cornerRadius = 5
label.layer.masksToBounds = true

上面的方法不可取,會(huì)出發(fā)離屏渲染:
*如果能夠只用 cornerRadius 解決問題,就不用優(yōu)化。

*如果必須設(shè)置 masksToBounds,可以參考圓角視圖的數(shù)量,如果數(shù)量較少(一頁只有幾個(gè))也可以考慮不用優(yōu)化。

*UIImageView的圓角可以通過直接截取圖片實(shí)現(xiàn)。其他視圖的圓角可以通過Core Graphics畫出圓角矩形實(shí)現(xiàn)

39.如何提升 tableview 的流暢度?
本質(zhì)上是降低 CPU、GPU 的工作,從這兩個(gè)大的方面去提升性能。

*CPU:對象的創(chuàng)建和銷毀、對象屬性的調(diào)整、布局計(jì)算、文本的計(jì)算和排版、圖片的格式轉(zhuǎn)換和解碼、圖像的繪制
*GPU:紋理的渲染
40.如何優(yōu)化 APP 的電量?
程序的耗電主要在以下四個(gè)方面:CPU,定位,網(wǎng)絡(luò),圖像
*盡可能降低CPU,GPU的功耗
*少用定時(shí)器
*優(yōu)化I/O操作:
*不要頻繁寫入小數(shù)據(jù),積攢到一定數(shù)量在寫入
*讀寫大量數(shù)據(jù)可使用 Dispatch_io ,GCD 內(nèi)部已經(jīng)做了優(yōu)化。
*數(shù)據(jù)量比較大,建議使用數(shù)據(jù)庫
*網(wǎng)絡(luò)方面的優(yōu)化
*減少壓縮網(wǎng)絡(luò)數(shù)據(jù)
*請求數(shù)據(jù)返回相同,使用NSCache緩存
*使用斷點(diǎn)續(xù)傳,避免因網(wǎng)絡(luò)失敗后重新下載
*網(wǎng)絡(luò)不可用時(shí),不提供網(wǎng)絡(luò)請求
*長時(shí)間網(wǎng)絡(luò)請求,提供取消操作
*批量傳輸,下載視頻流的時(shí)候,盡量一大塊一大塊的進(jìn)行下載,廣告可以一次下
載多個(gè)
*定位層面的優(yōu)化
* 如果只是需要快速確定用戶位置,最好用 CLLocationManager 的 requestLocation 方法。定位完成后,會(huì)自動(dòng)讓定位硬件斷電
*如果不是導(dǎo)航應(yīng)用,盡量不要實(shí)時(shí)更新位置,定位完畢就關(guān)掉定位服務(wù)
*盡量降低定位精度,比如盡量不要使用精度最高的 kCLLocationAccuracyBest
*需要后臺(tái)定位時(shí),盡量設(shè)置 pausesLocationUpdatesAutomatically 為 YES,如果用戶不太可能移動(dòng)的時(shí)候系統(tǒng)會(huì)自動(dòng)暫停位置更新
*盡量不要使用 startMonitoringSignificantLocationChanges,優(yōu)先考慮 startMonitoringForRegion:
*硬件檢測優(yōu)化
*用戶移動(dòng)、搖晃、傾斜設(shè)備時(shí),會(huì)產(chǎn)生動(dòng)作(motion)事件,這些事件由加速度計(jì)、陀螺儀、磁力計(jì)等硬件檢測。在不需要檢測的場合,應(yīng)該及時(shí)關(guān)閉這些硬件

41.如何有效降低 APP 包的大小?
可執(zhí)行文件
*編譯器優(yōu)化
**Strip Linked Product、Make Strings Read-Only、Symbols Hidden by Default 設(shè)置為 YES
**去掉異常支持,Enable C++ Exceptions、Enable Objective-C Exceptions 設(shè)置為 NO, Other C Flags 添加 -fno-exceptions
*利用 AppCode 檢測未使用的代碼:菜單欄 -> Code -> Inspect Code
*編寫LLVM插件檢測出重復(fù)代碼、未被調(diào)用的代碼
資源
*資源包括 圖片、音頻、視頻 等

42.什么是 離屏渲染?什么情況下會(huì)觸發(fā)?該如何應(yīng)對?
離屏渲染就是在當(dāng)前屏幕緩沖區(qū)以外,新開辟一個(gè)緩沖器進(jìn)行操作
離屏渲染出發(fā)的場景有以下:
*圓角(maskToBounds并用才會(huì)觸發(fā))
*圖層蒙版
*陰影
*光柵化
為什么要避免離屏渲染?
CPU GPU 在繪制渲染視圖時(shí)做了大量的工作。離屏渲染發(fā)生在 GPU 層面上,會(huì)創(chuàng)建新的渲染緩沖區(qū),會(huì)觸發(fā) OpenGL 的多通道渲染管線,圖形上下文的切換會(huì)造成額外的開銷,增加 GPU 工作量。如果 CPU GPU 累計(jì)耗時(shí) 16.67 毫秒還沒有完成,就會(huì)造成卡頓掉幀。

43.NSThread+runloop實(shí)現(xiàn)常駐線程
*由于每次開辟子線程都會(huì)消耗cpu,在需要頻繁使用子線程的情況下,頻繁開辟子線程會(huì)消耗大量的cpu,而且創(chuàng)建線程都是任務(wù)執(zhí)行完成之后也就釋放了,不能再次利用,那么如何創(chuàng)建一個(gè)線程可以讓它可以再次工作呢?也就是創(chuàng)建一個(gè)常駐線程。

+ (NSThread *)shareThread {
    
    static NSThread *shareThread = nil;
    
    static dispatch_once_t oncePredicate;
    
    dispatch_once(&oncePredicate, ^{
        
        shareThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadTest2) object:nil];
        
        [shareThread setName:@"threadTest"];
        
        [shareThread start];
    });
    
    return shareThread;
}

+ (void)threadTest
{
    @autoreleasepool {
        
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        
        [runLoop run];
    }
}

44.自旋鎖與互斥鎖
自旋鎖會(huì)忙等: 所謂忙等,即在訪問被鎖資源時(shí),調(diào)用者線程不會(huì)休眠,而是不停循環(huán)在那里,直到被鎖資源釋放鎖。
互斥鎖會(huì)休眠: 所謂休眠,即在訪問被鎖資源時(shí),調(diào)用者線程會(huì)休眠,此時(shí)cpu可以調(diào)度其他線程工作。直到被鎖資源釋放鎖。此時(shí)會(huì)喚醒休眠線程。

45.內(nèi)存中的5大區(qū)分別是什么?
棧區(qū)(stack):由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其 操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。
堆區(qū)(heap):一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表。
全局區(qū)(靜態(tài)區(qū))(static):全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的 全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 - 程序結(jié)束后由系統(tǒng)釋放。
文字常量區(qū):常量字符串就是放在這里的。 程序結(jié)束后由系統(tǒng)釋放。
程序代碼區(qū):存放函數(shù)體的二進(jìn)制代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內(nèi)容

  • 1.為什么說Objective-C是一門動(dòng)態(tài)的語言? 1.object-c類的類型和數(shù)據(jù)變量的類型都是在運(yùn)行是確定...
    墨徠閱讀 729評論 0 0
  • UIKit 1.UIView 和 CALayer 是什么關(guān)系? UIView 繼承 UIResponder,而 U...
    Sephiroth_Ma閱讀 2,235評論 0 25
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,592評論 0 11
  • 彩排完,天已黑
    劉凱書法閱讀 4,260評論 1 3
  • 沒事就多看看書,因?yàn)楦褂性姇鴼庾匀A,讀書萬卷始通神。沒事就多出去旅游,別因?yàn)闆]錢而找借口,因?yàn)橹灰闶〕詢€用,來...
    向陽之心閱讀 4,806評論 3 11