1齐饮、ios一個(gè)對象占用多少字節(jié)?
ios系統(tǒng)分配了16byte(16字節(jié))內(nèi)存空間舷礼,通過malloc_size可以獲取到谈火。
通過函數(shù)class_getInstanceSize獲取實(shí)例對象占用內(nèi)存大小為8byte。因?yàn)橄到y(tǒng)分配內(nèi)存空間規(guī)律是16的倍肌幽。
2晚碾、如何計(jì)算圖片加載內(nèi)存中占用大小喂急?
圖片內(nèi)存大小的計(jì)算公式 寬度 * 高度 * bytesPerPixel/8格嘁。
bytesPerPixel : 每個(gè)像素所占的字節(jié)數(shù)。
內(nèi)存計(jì)算:像素高*像素寬*4(4是每個(gè)像素占用字節(jié)數(shù))
但是通常情況下顏色還有alpha通道也是8位 也就是傳說中的RGBA廊移,總共32位糕簿。
取內(nèi)存:用NSHashtable,弱引用持有對象狡孔。將圖片的對象放到這個(gè)弱引用的hash表中懂诗,可以實(shí)時(shí)查看當(dāng)前仍存活的所有圖片對象,并據(jù)此計(jì)算圖片占用的內(nèi)存
3步氏、VC生命周期
initialize:類初始化方法
init:實(shí)例初始化方法
inintWithCoder:從歸檔初始化响禽,如果使用storyboard或xib
loadview:加載view
viewdidload:view加載完畢
viewwillLaoutSubviews:控制器的view將要布局子控件
viewdidlayoutSubviews:控制器view布局子控件完成
viewwillappear:控制器的view將要顯示
viewdidappear:控制器view完全顯示
viewwilldisappear:控制器的view即將消失
viewdiddisappear:控制器的view完全消失
viewdidunload
dealloc
4、多個(gè)網(wǎng)絡(luò)請求完畢執(zhí)行操作荚醒?
gcd三種方式
1.dispatch_group_t控制
2.信號(hào)量dispatch_semaphore_t控制
3.柵欄塊dispatch_barrier_async控制
注意:所有任務(wù)必須在同一個(gè)隊(duì)列芋类;
隊(duì)列不能使用全局隊(duì)列,需要自己創(chuàng)建隊(duì)列界阁。
5侯繁、為什么NSArray要用copy?NSMutableArray要用strong修飾泡躯?
1.如果NSArray用strong修飾贮竟,由于是強(qiáng)引用丽焊,副本對象數(shù)組和源對象數(shù)組只是指向同一塊內(nèi)存區(qū)域,這樣會(huì)造成副本對象會(huì)隨著源對象數(shù)組改變而改變咕别。
2.如果NSMutableArray用copy修飾技健,可變數(shù)組會(huì)變成不可變數(shù)組。用copy關(guān)鍵字惰拱,調(diào)用setter方法后雌贱, 進(jìn)行了深拷貝,并且拷貝的對象是copy的偿短,所以copy修飾NSMutableArray被視為NSArray了欣孤,再調(diào)用可變數(shù)組方法就會(huì)崩潰。
6昔逗、方法延遲執(zhí)行多種方法降传?
1.performSelector【非阻塞】
[self performSelector:@selector(delayMethod) withObject:nil/*可傳任意類型參數(shù)*/ afterDelay:2.0];
2.NSTimer【非阻塞】
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(delayMethod) userInfo:nil repeats:NO];
3.NSThread線程的sleep【阻塞】
[NSThread sleepForTimeInterval:2.0];
4.GCD【非阻塞】
__block ViewController *weakSelf = self;
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
dispatch_after(delayTime, dispatch_get_main_queue(), ^{
[weakSelf delayMethod];
});
5、面向過程與面向?qū)ο髤^(qū)別
面向過程:是一種以過程為中心的編程思想勾怒,分析出解決問題的步驟婆排,然后用函數(shù)把這些步驟一一實(shí)現(xiàn)。面向過程數(shù)據(jù)和對數(shù)據(jù)操作是分離的控硼。
(1)優(yōu)點(diǎn):性能比面向?qū)ο蟾咴舐郏驗(yàn)轭愓{(diào)用需要實(shí)例化艾少,開銷大卡乾,比較耗資源。
(2)缺點(diǎn):沒有面向?qū)ο笠拙S護(hù)缚够,易復(fù)用幔妨,易擴(kuò)展。
面向?qū)ο螅簩⑹聞?wù)對象化谍椅,通過對象通信來解決問題误堡。面向?qū)ο缶幊讨袛?shù)據(jù)和對數(shù)據(jù)操作在一起的。
(1)優(yōu)點(diǎn):由于面向?qū)ο蠓庋b雏吭、繼承锁施、多態(tài)特性,可以設(shè)計(jì)低耦合杖们,系統(tǒng)更靈活悉抵,更易于維護(hù)。
(2)缺點(diǎn):性能比面向過程低摘完。
6姥饰、封裝、繼承孝治、多態(tài)
封裝:即隱藏對象的屬性和實(shí)現(xiàn)方法列粪,僅對外提供公共的訪問方法审磁。
繼承:子類繼承父類非私有的屬性和方法,子類可以添加自己的屬性和方法岂座,子類可以重新定義父類的方法态蒂。
多態(tài):
1.沒有繼承就沒有多態(tài)
2.代碼體現(xiàn):父類類型指針指向子類對象
3.好處:如果函數(shù)方法參數(shù)使用的是父類類型,則可以傳入父類和子類對象费什,而不用去調(diào)用多個(gè)來對類進(jìn)行匹配了吃媒。
4.局限性:父類類型變量不能直接調(diào)用子類持有的方法,如果必須調(diào)用吕喘,須強(qiáng)制轉(zhuǎn)換為子類后再調(diào)用赘那。
【定義為父類類型,實(shí)際調(diào)用為子類類型氯质,通過調(diào)用子類類型調(diào)用子類的方法】
【打印機(jī)- 彩色打印機(jī) -黑白打印機(jī)例子】
7募舟、面向?qū)ο罅鶄€(gè)基本原則
1.單一職責(zé)原則:一個(gè)類功能要單一,一個(gè)類只負(fù)責(zé)一個(gè)職責(zé)闻察。
2.開放封閉原則:對外擴(kuò)展開放拱礁,對修改關(guān)閉。
3.里氏替換原則:任何使用基類的地方都能使用子類進(jìn)行替換辕漂,替換子類后呢灶,系統(tǒng)能正常工作。
4.接口隔離原則:接口顆粒度小化钉嘹,建立單一接口鸯乃,接口要小而專,不能大而全跋涣。
5.依賴倒置原則:我們的類要依賴于抽象缨睡,而依賴于具體,通過抽象使各個(gè)類或模塊的實(shí)現(xiàn)彼此獨(dú)立陈辱,不想糊影響奖年,實(shí)現(xiàn)模塊間松耦合。
6.迪米特原則:一個(gè)對象盡可能少的去了解其他對象沛贪,消除耦合陋守。
8、dispatch_once怎么實(shí)現(xiàn)線程安全利赋?
此函數(shù)通采用“原子訪問”來查詢標(biāo)記水评,以判斷其所對應(yīng)的代碼原來是否已經(jīng)執(zhí)行過。
+ (instancetype)sharedInstance
{
/*定義相應(yīng)類實(shí)例的靜態(tài)變量隐砸;
意義:函數(shù)內(nèi)定義靜態(tài)變量之碗,無論該函數(shù)被調(diào)用多少次,
在內(nèi)存中只初始化一次季希,并且能保存最后一次賦的值
*/
static ClassName *instance = nil;
/*定義一個(gè)dispatch_once_t(其實(shí)也就是整型)靜態(tài)變量褪那,
意義:作為標(biāo)識(shí)下面dispatch_once的block是否已執(zhí)行過幽纷。
static修飾會(huì)默認(rèn)將其初始化為0,當(dāng)值為0時(shí)才會(huì)執(zhí)行block博敬。
當(dāng)block執(zhí)行完成友浸,底層會(huì)將onceToken設(shè)置為1,這也就是為什
么要傳onceToken的地址(static修飾的變量可以通過地址修改
onceToken的值)偏窝,同時(shí)底層會(huì)加鎖來保證這個(gè)方法是線程安全的
*/
static dispatch_once_t onceToken;
/*只要當(dāng)onceToken == 0時(shí)才會(huì)執(zhí)行block收恢,否則直接返回靜態(tài)變量instance*/
dispatch_once(&onceToken, ^{
instance = [[ClassName alloc] init];
//...
});
return instance;
}
1. 在瀏覽器地址欄輸入U(xiǎn)RL
2. 瀏覽器查看緩存伦意,如果請求資源在緩存中并且新鮮,跳轉(zhuǎn)到轉(zhuǎn)碼步驟
1. 如果資源未緩存硼补,發(fā)起新請求
2. 如果已緩存驮肉,檢驗(yàn)是否足夠新鮮,足夠新鮮直接提供給客戶端已骇,否則與服務(wù)器進(jìn)行驗(yàn)證离钝。
3. 檢驗(yàn)新鮮通常有兩個(gè)HTTP頭進(jìn)行控制`Expires`和`Cache-Control`:
* HTTP1.0提供Expires,值為一個(gè)絕對時(shí)間表示緩存新鮮日期
* HTTP1.1增加了Cache-Control: max-age=,值為以秒為單位的最大新鮮時(shí)間
3. 瀏覽器解析URL獲取協(xié)議褪储,主機(jī)卵渴,端口,path
4. 瀏覽器組裝一個(gè)HTTP(GET)請求報(bào)文
5. 瀏覽器獲取主機(jī)ip地址鲤竹,過程如下:
1. 瀏覽器緩存
2. 本機(jī)緩存
3. hosts文件
4. 路由器緩存
5. ISP DNS緩存
6. DNS遞歸查詢(可能存在負(fù)載均衡導(dǎo)致每次IP不一樣)
6. 打開一個(gè)socket與目標(biāo)IP地址浪读,端口建立TCP鏈接,三次握手如下:
1. 客戶端發(fā)送一個(gè)TCP的SYN=1宛裕,Seq=X的包到服務(wù)器端口
2. 服務(wù)器發(fā)回SYN=1瑟啃, ACK=X+1论泛, Seq=Y的響應(yīng)包
3. 客戶端發(fā)送ACK=Y+1揩尸, Seq=Z
7. TCP鏈接建立后發(fā)送HTTP請求
8. 服務(wù)器接受請求并解析,將請求轉(zhuǎn)發(fā)到服務(wù)程序屁奏,如虛擬主機(jī)使用HTTP Host頭部判斷請求的服務(wù)程序
9. 服務(wù)器檢查HTTP請求頭是否包含緩存驗(yàn)證信息如果驗(yàn)證緩存新鮮岩榆,返回304等對應(yīng)狀態(tài)碼
10. 處理程序讀取完整請求并準(zhǔn)備HTTP響應(yīng),可能需要查詢數(shù)據(jù)庫等操作
11. 服務(wù)器將響應(yīng)報(bào)文通過TCP連接發(fā)送回瀏覽器
12. 瀏覽器接收HTTP響應(yīng)坟瓢,然后根據(jù)情況選擇關(guān)閉TCP連接或者保留重用勇边,關(guān)閉TCP連接的四次握手如下:
1. 主動(dòng)方發(fā)送Fin=1, Ack=Z折联, Seq= X報(bào)文
2. 被動(dòng)方發(fā)送ACK=X+1粒褒, Seq=Z報(bào)文
3. 被動(dòng)方發(fā)送Fin=1, ACK=X诚镰, Seq=Y報(bào)文
4. 主動(dòng)方發(fā)送ACK=Y奕坟, Seq=X報(bào)文
13. 瀏覽器檢查響應(yīng)狀態(tài)嗎:是否為1XX祥款,3XX, 4XX月杉, 5XX刃跛,這些情況處理與2XX不同
14. 如果資源可緩存,進(jìn)行緩存
15. 對響應(yīng)進(jìn)行解碼(例如gzip壓縮)
16. 根據(jù)資源類型決定如何處理(假設(shè)資源為HTML文檔)
17. 解析HTML文檔苛萎,構(gòu)件DOM樹桨昙,下載資源,構(gòu)造CSSOM樹腌歉,執(zhí)行js腳本蛙酪,這些操作沒有嚴(yán)格的先后順序,以下分別解釋
18. 構(gòu)建DOM樹:
1. Tokenizing:根據(jù)HTML規(guī)范將字符流解析為標(biāo)記
2. Lexing:詞法分析將標(biāo)記轉(zhuǎn)換為對象并定義屬性和規(guī)則
3. DOM construction:根據(jù)HTML標(biāo)記關(guān)系將對象組成DOM樹
19. 解析過程中遇到圖片翘盖、樣式表滤否、js文件,啟動(dòng)下載
20. 構(gòu)建CSSOM樹:
1. Tokenizing:字符流轉(zhuǎn)換為標(biāo)記流
2. Node:根據(jù)標(biāo)記創(chuàng)建節(jié)點(diǎn)
3. CSSOM:節(jié)點(diǎn)創(chuàng)建CSSOM樹
21. [根據(jù)DOM樹和CSSOM樹構(gòu)建渲染樹]
22. js解析如下:
23. 顯示頁面(HTML解析過程中會(huì)逐步顯示頁面)
10最仑、KVO監(jiān)聽可變數(shù)組count變化藐俺?
繼承NSObject創(chuàng)建一個(gè)model類,model類添加一個(gè)NSMutaleArray數(shù)組的屬性modelArr泥彤,進(jìn)行初始化欲芹。
VC里定義一個(gè)model屬性,添加model的KVO監(jiān)聽吟吝,監(jiān)聽modelArr屬性值變化菱父,并重寫監(jiān)聽方法,通過keypath判斷modelArr的變化剑逃。
11浙宜、load和initialize
(http://www.reibang.com/p/c52d0b6ee5e9)
12、Block幾種類型蛹磺?
1.全局block:globalBlock粟瞬,不使用外部變量的block,存儲(chǔ)在已初始化數(shù)據(jù)區(qū)
- (void)block0 {
// 聲明: typedef NSString *(^MyBlock)(NSString *str);
MyBlock block = ^(NSString *str){
NSLog(@"處理一些無關(guān)于外部屬性的事務(wù)");
return str;
};
block(@"");
NSLog(@"block類型%@",block);
}
2.棧block:StackBlock萤捆,使用外部變量并且未進(jìn)行copy操作的block裙品。保存在棧中的block,沒有用copy去修飾并且訪問了外部變量俗或,你的block類型就是這種類型市怎,會(huì)在函數(shù)調(diào)用結(jié)束被銷毀 (需要在MRC)
MRC環(huán)境下:訪問外界變量的block默認(rèn)存儲(chǔ)在棧區(qū)。
ARC環(huán)境下:訪問外界變量的block默認(rèn)存放在堆中辛慰,實(shí)際上是先放在棧區(qū)区匠,在ARC情況下自動(dòng)又拷貝到堆區(qū),自動(dòng)釋放帅腌。
通過官方文檔可以看出驰弄,復(fù)制到堆區(qū)的主要目的就是保存block的狀態(tài)蝠筑,延長其生命周期。因?yàn)閎lock如果在棧上的話揩懒,其所屬的變量作用域結(jié)束什乙,該block就被釋放掉,block中的__block變量也同時(shí)被釋放掉已球。為了解決棧塊在其變量作用域結(jié)束之后被釋放掉的問題臣镣,我們就需要把block復(fù)制到堆中。
- (void)block1 {
int a = 1;
NSLog(@"block111類型%@",^{ NSLog(@"block 0:%i", a); });
}
3智亮、堆block忆某,NSMallocBlock, 保存在堆中的block 此類型blcok是用copy修飾出來的block 它會(huì)隨著對象的銷毀而銷毀阔蛉,只要對象不銷毀弃舒,我們就可以調(diào)用的到在堆中的block。
int a = 5;
self.block1 = ^(NSString *str, UIColor *color){
NSLog(@"%d",a);
};
NSLog(@"block1=%@",self.block1);
13-1状原、block為什么用copy修飾聋呢?
首先,block是一個(gè)將函數(shù)及其上下文封裝起來的一個(gè)對象颠区。理論是可以retain削锰,release的,但是創(chuàng)建block默認(rèn)是在棧上的毕莱,而不是在堆上器贩,所以他的作用域僅限創(chuàng)建時(shí)候的當(dāng)前上下文,出了作用域調(diào)用該block朋截,程序會(huì)崩潰蛹稍。
1.一般情況不需要自行copy或者retain 一個(gè)block,只有當(dāng)你需要在block定義域以外地方調(diào)用時(shí)才需要copy部服。
2.其實(shí)copy和strong都一樣唆姐,因?yàn)閎lock的retain就是用copy來實(shí)現(xiàn)的。
13-2饲宿、block截獲變量
局部變量:截獲其值
局部靜態(tài)變量:截獲其指針
全局變量:不截獲
全局靜態(tài)變量:不截獲
外部變量:截獲其指針及其修飾符
常量存儲(chǔ)在常量區(qū)厦酬,全局變量/靜態(tài)變量存儲(chǔ)在全局區(qū)/靜態(tài)區(qū)。
變量:1.1 基本數(shù)據(jù)類型/非oc對象一般存儲(chǔ)在棧區(qū)瘫想,
1.2 oc對象一般是存儲(chǔ)在堆區(qū)
oc對象有指針概念,指針變量存儲(chǔ)在棧區(qū)昌讲,而指針存放的是對象在堆區(qū)的地址国夜。所以我們是通過棧區(qū)的指針變量來索引堆中地址,從而訪問對象的短绸。
Block不允許修改外部變量的值车吹,這里所說的外部變量的值筹裕,指的是棧中指針的地址。要想在Block內(nèi)修改“外部變量”的值窄驹,必須被__block修飾朝卒。
auto類型的局部變量,可以被block捕獲乐埠,但是不能修改值
__block可以解決block內(nèi)部無法修改外部auto變量的問題,
__block修飾的變量抗斤,編譯器會(huì)把它包裝成一個(gè)對象,然后我們的這個(gè)成員變量放到了這個(gè)對象的內(nèi)部
14丈咐、深淺拷貝瑞眼?
copy和mutableCopy是NSObject的方法,很多系統(tǒng)容器已經(jīng)實(shí)現(xiàn)了這個(gè)方法棵逊,如果自定義對象想使用這兩個(gè)方法伤疙,必須實(shí)現(xiàn)NSCopying協(xié)議和NSMutableCopying協(xié)議。
指針拷貝
內(nèi)容拷貝
例子:
1. [NSArray copy] ->不可變數(shù)組辆影,淺拷貝
2. [NSArray mutableCopy] -> 可變數(shù)組徒像,深拷貝
3. [NSMutableArray copy] -> 不可變數(shù)組,深拷貝
4. [NSMutableArray mutableCopy] -> 可變數(shù)組蛙讥,深拷貝
15厨姚、當(dāng)點(diǎn)擊屏幕上的一個(gè)按鈕,這個(gè)過程具體發(fā)生了什么键菱?
UIResponder:{
UIApplication
UIView -> UIControl -> UIButton,UISlider
UIViewController
}
https://www.cnblogs.com/machao/p/5471094.html
1谬墙、用戶觸摸屏幕,系統(tǒng)硬件進(jìn)程會(huì)獲取到這個(gè)事件经备,將事件簡單封裝后存入系統(tǒng)中拭抬,硬件檢測進(jìn)程會(huì)將事件放到APP檢測的那個(gè)端口。
2侵蒙、APP啟動(dòng)主線程runloop會(huì)注冊一個(gè)端口事件造虎,來檢測事件的發(fā)生。當(dāng)事件到達(dá)會(huì)喚起當(dāng)前APP主線程的runloop纷闺。
3算凿、最后系統(tǒng)會(huì)判斷該次觸摸是否導(dǎo)致了一個(gè)新的事件,如果是第一個(gè)手指開始觸碰犁功,系統(tǒng)會(huì)從響應(yīng)網(wǎng)中尋找響應(yīng)鏈氓轰。
響應(yīng)者鏈條:很多響應(yīng)者對象(繼承自UIResponder的對象)一起組合起來的鏈條稱之為響應(yīng)者鏈條。
內(nèi)存溢出:指程序申請內(nèi)存時(shí)署鸡,沒有足夠的空間供其使用;
內(nèi)存泄露:指程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間靴庆,
1.排查方法:
1.靜態(tài)分析方法(Analyze)
2.動(dòng)態(tài)分析(Instrument 工具庫leaks)
2.原因分析:ARC根本原因還是存在循環(huán)引用时捌,導(dǎo)致一些內(nèi)存無法釋放。
1.VC存在timer炉抒,合適時(shí)機(jī)invalidate
2.VC中的delegate奢讨,代理盡量使用weak修飾
3.VC中使用block,在block外部對弱化self焰薄,再在block內(nèi)部強(qiáng)化已經(jīng)弱化的weakSelf
17拿诸、野指針:指針指向的對象已經(jīng)被回收掉了,這個(gè)指針叫做野指針蛤奥。
18佳镜、線程安全?加鎖
自旋鎖會(huì)忙等: 所謂忙等凡桥,即在訪問被鎖資源時(shí)蟀伸,調(diào)用者線程不會(huì)休眠,而是不停循環(huán)在那里缅刽,直到被鎖資源釋放鎖啊掏。
互斥鎖會(huì)休眠: 所謂休眠,即在訪問被鎖資源時(shí)衰猛,調(diào)用者線程會(huì)休眠迟蜜,此時(shí)cpu可以調(diào)度其他線程工作。直到被鎖資源釋放鎖啡省。此時(shí)會(huì)喚醒休眠線程
遞歸鎖:遞歸鎖可以被同一線程多次請求娜睛,而不會(huì)引起死鎖。這主要是用在循環(huán)或遞歸操作中卦睹。
19畦戒、HTTP總結(jié)
20、MVC结序,MVP障斋,MVVM
http://www.reibang.com/p/32078fcd704d
21、[[NSMutableArray alloc]init]和[NSMutableArray array]的區(qū)別
[[NSMutableArray alloc]init] alloc分配內(nèi)存徐鹤,init初始化垃环,需要手動(dòng)釋放
[NSMutableArray array] 不需要手動(dòng)release,遵循autoreleasepool機(jī)制
在ARC(自動(dòng)引用計(jì)數(shù))中兩種方式并沒什么區(qū)別
22返敬、說一下dispatch_group_t和dispatch_barrier_sync的區(qū)別嗎
dispatch_group_t:相關(guān)函數(shù):dispatch_group_t創(chuàng)建組遂庄,dispatch_group_async異步處理,dispatch_group_notify監(jiān)視這些處理結(jié)果救赐。
一旦檢測到所有處理執(zhí)行結(jié)束涧团,將結(jié)束的處理追加到dispatch queue中只磷,這就是使用dispatch_group的原因经磅。
===============================================
dispatch_barrier_sync && dispatch_barrier_async
將隊(duì)列一分為二泌绣,前面任務(wù)執(zhí)行完畢才能執(zhí)行 dispatch_barrier_sync的任務(wù)(主線程),然后才執(zhí)行隊(duì)列后面任務(wù)。 dispatch_barrier_async在子線程中執(zhí)行预厌,不會(huì)阻塞當(dāng)前線程阿迈,將自己任務(wù)插入隊(duì)列之后,不會(huì)等待自己任務(wù)結(jié)束轧叽,會(huì)繼續(xù)吧后面任務(wù)插入隊(duì)列苗沧,然后等待自己任務(wù)結(jié)束,才執(zhí)行后面任務(wù)炭晒。
23待逞、UI繪制原理&系統(tǒng)/異步繪制流程
##UIView繪制原理:
當(dāng)我們調(diào)用uiview的setNeedDisplay方法以后,實(shí)際并沒有立刻發(fā)生當(dāng)前視圖的繪制工作网严。
1.當(dāng)調(diào)用UIView的setNeedDisplay后
2.系統(tǒng)會(huì)立刻調(diào)用view的layer的同名方法识樱,之后相當(dāng)于在layer上打了一個(gè)臟標(biāo)記
3.當(dāng)runloop將要結(jié)束的時(shí)候,才會(huì)調(diào)用CALayer的display函數(shù)方法震束,然后進(jìn)入當(dāng)前視圖的真正繪制流程中怜庸,
4.CALayer的display方法,在內(nèi)部會(huì)判斷l(xiāng)ayer的delegate是否響應(yīng)displayLayer這個(gè)方法
5.若不響應(yīng)垢村,則系統(tǒng)開始繪制流程
6.若響應(yīng)割疾,則開始異步繪制
##系統(tǒng)繪制流程:
1.首先CALayer內(nèi)部會(huì)創(chuàng)建一個(gè)CGContentextRef,在drawRect方法中嘉栓,可以通過上下文堆棧中的取出這個(gè)context宏榕,拿到的就是當(dāng)前視圖的上下文。
2.然后layr判斷是否有代理侵佃,若沒有麻昼,則調(diào)用CALayer的drawInContext
3.若有代理調(diào)用代理方法,然后做當(dāng)前視圖的繪制工作趣钱,在在合適的時(shí)機(jī)基于drawRect回調(diào)方法
4.drawRect 默認(rèn)操作是什么都不做涌献,我們可以做一些自定義繪制工作
5.最后再由CALayer上傳對應(yīng)的backing store給GPU,這里的backing store理解為位圖首有。
##異步繪制:
【基于layer的delegate燕垃,如果實(shí)現(xiàn)了displaylayer方法,就可以進(jìn)入異步繪制流程中】
1.通過子線程的切換井联,在子線程中做位圖繪制卜壕,此時(shí)主線程可以做些其他工作
2.再回到主隊(duì)列中,提交這個(gè)位圖烙常,設(shè)置給CALayer的contents屬性轴捎。
子線程繪制:
1.通過CGBitmapCOntextCreat方法鹤盒,創(chuàng)建位圖上下文
2.通過coreGraphic相關(guān)API,做一些UI控件的一些繪制工作
3.之后通過CGBitmapContextImage方法侦副,根據(jù)所繪制的上下文侦锯,生成一張CGImag圖片。
24秦驯、(iOS中的SEL和IMP)[http://www.reibang.com/p/4a09d5ebdc2c]
SEL:類成員方法的指針尺碰, SEL只是方法編號(hào)
IMP:一個(gè)函數(shù)指針,保存了方法的地址
關(guān)系:
每一個(gè)繼承于NSObject的類都能自動(dòng)獲得runtime的支持译隘,在這樣一個(gè)類中亲桥,又一個(gè)isa指針,指向該類定義的數(shù)據(jù)結(jié)構(gòu)體固耘,這個(gè)結(jié)構(gòu)體是由編譯器編譯時(shí)為類創(chuàng)建的题篷。這個(gè)結(jié)構(gòu)體包含了指向父類的指針和dispatch table,這是一張SEL和IMP的對應(yīng)表厅目。
方法編號(hào)SEL通過dispatch table表尋找對應(yīng)的IMP番枚,IMP時(shí)一個(gè)函數(shù)指針,然后執(zhí)行方法璧瞬。
25户辫、
dispatch_queue_t quete = dispatch_queue_create("com.taikang.com", DISPATCH_QUEUE_SERIAL);
dispatch_async(quete, ^{
NSLog(@"1------%@", [NSThread currentThread]);
});
dispatch_async(quete, ^{
NSLog(@"2------%@", [NSThread currentThread]);
});
dispatch_sync(quete, ^{
NSLog(@"3------%@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"4------%@", [NSThread currentThread]);
});
NSLog(@"5------%@", [NSThread currentThread]);
輸出:1,嗤锉,2渔欢,,3瘟忱,奥额,5,访诱,垫挨,4
26、什么是method swizzling【黑魔法】
簡單說就是方法交換
在Objective-C中調(diào)用一個(gè)方法触菜,其實(shí)是向一個(gè)對象發(fā)送消息九榔,查找消息的唯一依據(jù)是selector的名字。利用Objective-C的動(dòng)態(tài)特性涡相,可以實(shí)現(xiàn)在運(yùn)行時(shí)偷換selector對應(yīng)的方法實(shí)現(xiàn)哲泊,達(dá)到給方法掛鉤的目的。
##應(yīng)用場景:
1.防止數(shù)組取值越界crash
2.改變app中所有按鈕的大小[替換setframe方法]
3.處理按鈕重復(fù)點(diǎn)擊[替換sendAction:to:forEvent:]
4.每個(gè)vc增加標(biāo)記催蝗,[替換viewdidload]
27切威、SDWebImageView 原理[http://www.reibang.com/p/ff9095de1753?utm_source=desktop&utm_medium=timeline]
[http://www.jishudog.com/5171/html]
1.入口 setImageWithURL:placeholderImage:options:會(huì)先把 placeholderImage顯示,然后 SDWebImageManager根據(jù) URL 開始處理圖片丙号。
2.進(jìn)入SDWebImageManager 類中downloadWithURL:delegate:options:userInfo:先朦,交給
SDImageCache從緩存查找圖片是否已經(jīng)下載
queryDiskCacheForKey:delegate:userInfo:.
3.先從內(nèi)存圖片緩存查找是否有圖片缰冤,如果內(nèi)存中已經(jīng)有圖片緩存,SDImageCacheDelegate回調(diào) imageCache:didFindImage:forKey:userInfo:到
SDWebImageManager喳魏。
4.SDWebImageManagerDelegate 回調(diào)
webImageManager:didFinishWithImage: 到 UIImageView+WebCache,等前端展示圖片棉浸。
5.如果內(nèi)存緩存中沒有,生成 `NSOperation `
添加到隊(duì)列截酷,開始從硬盤查找圖片是否已經(jīng)緩存涮拗。
6.根據(jù) URL的MD5值Key在硬盤緩存目錄下嘗試讀取圖片文件乾戏。這一步是在 NSOperation 進(jìn)行的操作迂苛,所以回主線程進(jìn)行結(jié)果回調(diào) notifyDelegate:。
7.如果上一操作從硬盤讀取到了圖片鼓择,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過小三幻, 會(huì)先清空內(nèi)存緩存)。SDImageCacheDelegate'回調(diào) imageCache:didFindImage:forKey:userInfo:`呐能。進(jìn)而回調(diào)展示圖片念搬。
8.如果從硬盤緩存目錄讀取不到圖片,說明所有緩存都不存在該圖片摆出,需要下載圖片朗徊, 回調(diào) imageCache:didNotFindImageForKey:userInfo:。
9.共享或重新生成一個(gè)下載器 SDWebImageDownloader開始下載圖片偎漫。
10.圖片下載由 NSURLConnection來做爷恳,實(shí)現(xiàn)相關(guān) delegate
來判斷圖片下載中、下載完成和下載失敗象踊。
11.connection:didReceiveData: 中利用 ImageIO做了按圖片下載進(jìn)度加載效果温亲。
12.connectionDidFinishLoading: 數(shù)據(jù)下載完成后交給 SDWebImageDecoder做圖片解碼處理。
13.圖片解碼處理在一個(gè) NSOperationQueue完成杯矩,不會(huì)拖慢主線程 UI.如果有需要 對下載的圖片進(jìn)行二次處理栈虚,最好也在這里完成,效率會(huì)好很多史隆。
14.在主線程 notifyDelegateOnMainThreadWithInfo:
宣告解碼完成 imageDecoder:didFinishDecodingImage:userInfo: 回調(diào)給 SDWebImageDownloader`魂务。
15.imageDownloader:didFinishWithImage:回調(diào)給 SDWebImageManager告知圖片 下載完成。
-16. 通知所有的 downloadDelegates下載完成泌射,回調(diào)給需要的地方展示圖片粘姜。
17.將圖片保存到 SDImageCache中,內(nèi)存緩存和硬盤緩存同時(shí)保存魄幕。寫文件到硬盤 也在以單獨(dú) NSOperation 完成相艇,避免拖慢主線程。
18.SDImageCache 在初始化的時(shí)候會(huì)注冊一些消息通知纯陨,
在內(nèi)存警告或退到后臺(tái)的時(shí) 候清理內(nèi)存圖片緩存坛芽,應(yīng)用結(jié)束的時(shí)候清理過期圖片留储。
28、同一個(gè)url咙轩,圖片更新時(shí)如何操作获讳?
[SDWebImageRefreshCached :將硬盤緩存交給系統(tǒng)自帶的NSURLCache去處理,當(dāng)同一個(gè)URL對應(yīng)的圖片經(jīng)常更改時(shí)可以用這種策略]
[http://www.reibang.com/p/d559cb3ca1b3?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation]
29活喊、通過view獲取view所在的viewcontroller
響應(yīng)鏈:
事件有觸摸事件丐膝,滑動(dòng)事件,遠(yuǎn)程控制事件钾菊。當(dāng)屏幕上發(fā)生了觸摸事件帅矗,最先響應(yīng)的是最外層view,然后依次傳遞給他的父view煞烫,然后再到viewcontroller浑此,再到application。通過這個(gè)思路滞详,查找所在vc
-(UIViewController *)findViewController:(UIView *)currentView{
for (UIView *next = currentView.superview;next;next = next.superview) {
UIResponder *responder = [next nextResponder];
if([responder isKindOfClass:[UIViewController class]]){
return (UIViewController *)responder;
}
}
return nil;
}
30凛俱、如何解決哈希沖突?哈希表在ios中的應(yīng)用料饥?
哈希表(Hash table蒲犬,也叫散列表),是根據(jù)關(guān)鍵碼值而直接進(jìn)行訪問的數(shù)據(jù)結(jié)構(gòu)岸啡,是一塊連續(xù)的存儲(chǔ)空間原叮。
哈希函數(shù)常用設(shè)計(jì):(1)直接定址法,哈希函數(shù)為線性函數(shù)凰狞;(2)平方取中法篇裁,平方后取中間幾位;(3)折疊法赡若,拆分進(jìn)行加法計(jì)算得到數(shù)值达布;(4)隨機(jī)數(shù)法。
哈希沖突:對于不同的關(guān)鍵字逾冬,經(jīng)過哈希函數(shù)計(jì)算以后的哈希值相同黍聂。
解決辦法:
1.開放定址法:一旦發(fā)生沖突就尋找下一個(gè)空的散列地址身腻,只要散列表足夠大,空的散列地址總能找到嘀趟。
2.再哈希法:有多個(gè)不同的哈希函數(shù),當(dāng)發(fā)生沖突時(shí)她按,使用第二個(gè)牛隅,第三個(gè)炕柔。媒佣。。等哈希函數(shù)計(jì)算地址默伍,直到無沖突欢嘿,雖然不易發(fā)生聚集,但是增加了計(jì)算時(shí)間也糊。
3.鏈地址法:每個(gè)哈希表節(jié)點(diǎn)都有一個(gè)next指針,多哈希表節(jié)點(diǎn)可以用next指針構(gòu)成一個(gè)單向鏈表显设,被分配到同一個(gè)索引上的多個(gè)節(jié)點(diǎn)可以用單向鏈表連起來。
4.建立公共溢出區(qū):將哈希表分為基本表和溢出表兩部分,凡是和基本表發(fā)生沖突的元素斗搞,一律填入溢出表。
哈希表在iOS應(yīng)用:[http://www.reibang.com/p/48709f466db9]
31允悦、成員變量和屬性區(qū)別?@dynamic與@synthesize的區(qū)別隙弛?
成員變量:
1.成員變量默認(rèn)修飾@protected
2.成員變量不會(huì)自動(dòng)生成set和get方法狞山,需要自己手動(dòng)實(shí)現(xiàn)
3.成員變量不能用.語法調(diào)用,因?yàn)闆]有set萍启,get方法,只能用->調(diào)用
屬性:
1.屬性默認(rèn)@protected
2.屬性會(huì)自動(dòng)生成get局服,set方法
3.屬性用.語法調(diào)用驳遵,點(diǎn)語法實(shí)際上調(diào)用的是set和get方法淫奔。
@synthesize:
為屬性添加一個(gè)實(shí)例變量名堤结,或者別名佳鳖,同時(shí)為該屬性生成setter/getter方法媒惕。
@dynamic:
告訴編譯器,屬性的setter和getter方法由用戶自己實(shí)現(xiàn)穿挨,不自動(dòng)生成肴盏。
set,get方法重寫:
-(NSString *)caption{
return _caption;
}
-(void)setCaption:(NSString *)caption{
_caption = caption;
}
直接這樣寫會(huì)報(bào)錯(cuò)菜皂,需要在@implementation實(shí)現(xiàn)中添加:
@synthesize caption=_caption; 即可。
32恍飘、KVO運(yùn)行時(shí)創(chuàng)建的分類與自定義創(chuàng)建分類重名?
例如:創(chuàng)建了一個(gè)NSNotification_A類母蛛。
編譯通過乳怎,因?yàn)镵VO是運(yùn)行時(shí)創(chuàng)建的,并不在編譯時(shí)刻蚪缀,但是此時(shí)KVO起不了作用。
可以手動(dòng)添加set方法违帆,添加willChangeValueForKey哩盲,didChangeValueForKey。
33廉油、property的作用是什么,有哪些關(guān)鍵詞班巩,分別是什么含義?
@property 是聲明屬性語法的抱慌,可以快速為實(shí)例變量創(chuàng)建存取器,并允許我們通過點(diǎn)語法使用存取器抑进。
@property是一個(gè)屬性訪問聲明,主要屬性分三類匿情,原子性信殊,存取器控制,內(nèi)存管理涡拘;
原子性:automic,鳄乏,nonautomic
讀取屬性:readwrite,姓赤,readonly
內(nèi)存管理:assign仲吏,蝌焚,retain,只洒,copy,成畦,
34涝开、父類的property是如何查找的
根據(jù)子類獲取父類所有屬性:
//獲取父類所有屬性
+(void)showStudentClassProperties
{
Class cls = [model4 class];
unsigned int count;
while (cls!=[NSObject class]) {
objc_property_t *properties = class_copyPropertyList(cls, &count);
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
NSLog(@"屬性名==%@",propertyName);
}
if (properties){
//要釋放
free(properties);
}
//得到父類的信息
cls = class_getSuperclass(cls);
}
}