1、相冊相關(guān)
PHAssetCollection 相冊集合
PHAsset 每一個相冊資源,從PHAssetCollection中獲取
modificationDate 修改時間,
PHFetchOptions一些操作
根據(jù)修改時間排序
PHFetchOptions *option = [[PHFetchOptions alloc] init];
option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:YES]];
2、weak的釋放原理
對象釋放 -> objc_release -> dealloc -> objc_rootdealloc ->
objc_dispose -> objc_destructinstance -> objc_clear_deaallocation ->
通過兩次hash索引找到weak表 把所有的引用全部置空。
3、autoreleasePool 的結(jié)構(gòu)和自動釋放池中的對象存儲過程,autoreleasePool的結(jié)構(gòu)
這個結(jié)構(gòu)體在初始化是調(diào)用objc_autoreleasePoolPush(),在析構(gòu)時調(diào)用objc_autoreleasePoolPop()。
每一個自動釋放池其實是一個雙向鏈表,鏈表的每一個結(jié)點就是這個AutoreleasePoolPage,每個AutoreleasePoolPage的大小為4096字節(jié)
調(diào)用objc_autoreleasePoolPop時,會使用一個POOL_SENTINEL(哨兵),根據(jù)傳入的哨兵對象地址找到哨兵對象所處的page。在當(dāng)前page中,將晚于哨兵對象插入的所有autorelease對象都發(fā)送一次- release消息,并向回移動next指針到正確位置。
因為自動釋放池是一個雙向鏈表,而且每一個page的空間有限,所以會存在當(dāng)前page已滿的情況,也就出現(xiàn)了一個自動釋放池跨越幾個page的情況,所以在release的時候,也要順著鏈表全部清理掉。
資源釋放是在runloop迭代結(jié)束時釋放的,而并非作用域結(jié)束。
4、NSSet、NSDictionary、NSArray
set、dic用的hash。array用的數(shù)組。對應(yīng)到可變類型。arrayM用了環(huán)形緩沖區(qū)。
5、查找方法調(diào)用流程
(1,按照方法名去cache_t中查找方法,找到了就直接調(diào)用。
(2,1中未找到,進入類對象方法列表中查找。這個列表包含了分類的方法。
(3,如果在方法列表中找到了方法,則首先將方法加入cache_t中,然后調(diào)用方法。
(4,如果在方法列表中未找到方法,會通過superclass找到父類,在父類中進行1、2、3步驟。
(5,如果最終未找到方法,會進入方法的動態(tài)解析階段。
6、解決方法未找到的crash?
重寫簽名方法,返回一個非nil的方法簽名,以及forwardInvocation方法。
7、cache__t的k和v?
Key---@select value ——imp
8、block捕獲變量
int val = 1; 值傳遞(根本原因:Block不允許修改棧中指針的內(nèi)容)
static int static_val = 1; 指針傳遞(非對象,存儲在靜態(tài)區(qū),局部靜態(tài)變量,因為是局部,所以外部無法訪問)
__block后被封裝成為結(jié)構(gòu)體
__block說明符將基本類型的數(shù)據(jù)封裝為結(jié)構(gòu)體類型(其中包含了isa指針),這其實就說明__block變量已經(jīng)是作為了一個對象在使用。這里也并不違背括號中說的block無法修改棧中數(shù)據(jù)。歸根結(jié)底還是因為棧是系統(tǒng)管理的,外部人員無法操控。
9、load()和initialize()區(qū)別
load 分類不會替換掉主類的方法。initialize會。
load啟動即可調(diào)用。initialize類使用時候調(diào)用,比alloc早。
load是根據(jù)函數(shù)地址直接調(diào)用,initialize是通過objc_msgSend調(diào)用。
先調(diào)用類的load, 在調(diào)用分類的load。先編譯的類, 優(yōu)先調(diào)用load, 調(diào)用子類的load之前, 會先調(diào)用父類的load。先編譯的分類, 優(yōu)先調(diào)用load
initialize 先初始化分類, 后初始化子類,通過消息機制調(diào)用, 當(dāng)子類沒有initialize方法時, 會調(diào)用父類的initialize方法, 所以父類的initialize方法會調(diào)用多次,調(diào)用多次的時候,獲取的類名會不一樣。擴展會把initialize攔腰折斷,只有擴展對應(yīng)的父類會調(diào)用,自己和自己的子類不會調(diào)用,只會調(diào)用對應(yīng)擴展。
10、圖層方法兩倍形變后,frame和bouns的變化,相對位置,絕對位置。
frame相對中心,框一個矩形。bounds不變。
11、nstimer不準(zhǔn)怎么辦?
加入特性mode。新建子線程去創(chuàng)建timer。使用gcd的dispath_source_t
12、strong和copy的區(qū)別
區(qū)別在于可變對象的淺拷貝和深拷貝。
13、IOS多線程三種方式的優(yōu)缺點
NSThread 輕量級。但是線程同步需要自己管理。
operation 無需關(guān)心線程。對gcd的封裝。
GCD 不是oc風(fēng)格,是c的。
14、iOS開發(fā)中的常用鎖以及性能對比
NSLock、dispatch_semaphore_t、synchronized。
synchronized性能最差,但是最方便。
15、異步改同步
《1、semaphore 《2、group 《3、bool值 《4、nslock
16、block會對外部局部變量進行淺拷貝,然后在block體內(nèi)使用該副本。
17、同步異步,串行并行隊列。
異步串行(n個隊列)會生成對應(yīng)個數(shù)線程(n)。異步并行(個n隊列)會生成多個線程(>=n)
18、DISPATCH_QUEUE_SERIAL_INACTIVE是啥?
未初始化的串行隊列,一般不用。
19、dispatch_barrier_sync和dispatch_barrier_async?
共同點:
《1、等待在它前面插入隊列的任務(wù)先執(zhí)行完
《2、等待他們自己的任務(wù)執(zhí)行完再執(zhí)行后面的任務(wù)
不同點:
《1、dispatch_barrier_sync將自己的任務(wù)插入到隊列的時候,需要等待自己的任務(wù)結(jié)束之后才會繼續(xù)插入被寫在它后面的任務(wù),然后執(zhí)行它們
《2、dispatch_barrier_async將自己的任務(wù)插入到隊列之后,不會等待自己的任務(wù)結(jié)束,它會繼續(xù)把后面的任務(wù)插入到隊列,然后等待自己的任務(wù)結(jié)束后才執(zhí)行后面任務(wù)。
barrier 在global_queue中失效。
20、LLVM編譯流程
LLVM是一個模塊化的、可重用的編譯器和工具鏈技術(shù)的集合,Clang 是 LLVM 的子項目。
clang -ccc-print-phases main.m
進行語法分析、語義分析以及生成中間代碼.LLVM核心庫還提供一個優(yōu)化器。
開啟bitcode優(yōu)化:
clang -emit-llvm -c main.m -o main.bc
生成匯編的命令:
clang -S -fobjc-arc main.m -o main.s
再生成目標(biāo)文件:
clang -fmodules -c main.m -o main.o
最后生成可執(zhí)行文件:
clang main.o -o main
過程:預(yù)處理(語法、詞法),編譯(編譯優(yōu)化),匯編,鏈接,綁定相應(yīng)變量或者常量。
21、優(yōu)化 App 的啟動時間實踐 iOS
其中 t1蘋果提供了內(nèi)建的測量方法, Xcode 中 Edit scheme -> Run -> Auguments 將環(huán)境變量 DYLD_PRINT_STATISTICS 設(shè)為 1….
算了,這個需要研究好久,不糾結(jié)了,畢竟不是干這個的。
22、事件傳遞與響應(yīng)?
當(dāng)我們觸摸屏幕的時候,為我們找到最合適的view。
每當(dāng)手機觸摸屏幕,操作系統(tǒng)會把事件傳遞給當(dāng)前的APP,在UIApplication接收到手指的事件之后,就會去調(diào)用 UIWindow 的 hitTest:withEvent: 方法,看看當(dāng)前點擊的點是不是在window內(nèi),如果是則繼續(xù)調(diào)用其subview的 hitTest:withEvent: 方法,直到找到最后需要的view。
hitTest:withEvent: 的內(nèi)部實現(xiàn)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (self.hidden || self.userInteractionEnabled == NO || self.alpha < 0.01 || [self pointInside:point withEvent:event]) {
return nil;
}
for (UIView *subView in self.subviews.reverseObjectEnumerator) {
UIView *hitView = [subView hitTest:[subView convertPoint:point fromView:self] withEvent:event];
if (hitView) {
return hitView;
}
}
return self;
}
傳遞與響應(yīng)正相反。
23、scrollview嵌套。
contentOffset用于限制滾動。
24、子線程是否要手動創(chuàng)建autoreleasepool
NSThread和NSOperationQueue開辟子線程需要手動創(chuàng)建autoreleasepool,GCD開辟子線程不需要手動創(chuàng)建autoreleasepool,因為GCD的每個隊列都會自行創(chuàng)建autoreleasepool
25、為什么不能在子線程刷新UI
為了安全,因為UIKit框架不是線程安全的,當(dāng)多個線程同時操作UI的時候,搶奪資源,導(dǎo)致崩潰,UI異常等問題。
即使子線程操作UI了,也僅僅是給人的印象是在子線程操作的,而實際上必須等到線程結(jié)束后到主線程更新UI,并且代碼處會出現(xiàn)紫色。
26、autoreleasePool 在何時被釋放?
第一個 Observer 監(jiān)視的事件是 Entry(即將進入Loop),其回調(diào)內(nèi)會調(diào)用 _objc_autoreleasePoolPush() 創(chuàng)建自動釋放池。其 order 是 -2147483647,優(yōu)先級最高,保證創(chuàng)建釋放池發(fā)生在其他所有回調(diào)之前。
第二個 Observer 監(jiān)視了兩個事件: BeforeWaiting(準(zhǔn)備進入休眠) 時調(diào)用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 釋放舊的池并創(chuàng)建新池;Exit(即將退出Loop) 時調(diào)用 _objc_autoreleasePoolPop() 來釋放自動釋放池。這個 Observer 的 order 是 2147483647,優(yōu)先級最低,保證其釋放池子發(fā)生在其他所有回調(diào)之后。
27、Runloop何時退出?
線程結(jié)束或者設(shè)置了過期時間。
28、互斥鎖、自旋鎖?
互斥鎖睡眠,自旋鎖死循環(huán)。
29、Block中捕獲全局、靜態(tài)、實例、局部變量是怎樣實現(xiàn)的?
自動變量是以值傳遞方式傳遞到Block的構(gòu)造函數(shù)里面去的。Block只捕獲Block中會用到的變量。由于只捕獲了自動變量的值,并非內(nèi)存地址,所以Block內(nèi)部不能改變自動變量的值。Block捕獲的外部變量可以改變值的是靜態(tài)變量,靜態(tài)全局變量,全局變量。
30、什么是內(nèi)存對齊?
對齊規(guī)則是按照成員的聲明順序,依次安排內(nèi)存,其偏移量為成員大小的整數(shù)倍,0看做任何成員的整數(shù)倍,最后結(jié)構(gòu)體的大小為最大成員的整數(shù)倍。
31、卡頓產(chǎn)生的原因?
離屏渲染、主線程大量運算。讓主線程干重活,例如網(wǎng)絡(luò)請求,讀寫大文件,復(fù)雜的運算 等一些耗費大量系統(tǒng)資源及時間的任務(wù)
32、crash原因?
調(diào)用野指針,數(shù)組越界,除零(arm貌似不會,x86系列會,因此iPhone好像不會有問題),未實現(xiàn)方法,函數(shù)不支持當(dāng)前系統(tǒng),空cell,列表中有nil,內(nèi)存越界。
33、iOS App的啟動過程?
加載dyld到App進程,加載動態(tài)庫(包括所依賴的所有動態(tài)庫),Rebase,Bind,初始化Objective C Runtime,其它的初始化代碼。
34、iOS圖像顯示原理和卡頓優(yōu)化?
先是cpu,進行UI布局,文本計算;執(zhí)行drawrect;圖像編碼,提交到GPU總線。Gpu依次進行頂點著色,圖元裝配,光柵化,片段著色,片段處理