1、父類實(shí)現(xiàn)深拷貝時(shí)唁情,子類如何實(shí)現(xiàn)深度拷貝疑苔。父類沒(méi)有實(shí)現(xiàn)深拷貝時(shí),子類如何實(shí)現(xiàn)深度拷貝甸鸟。
深拷貝同淺拷貝的區(qū)別:淺拷貝是指指針拷貝惦费,對(duì)一個(gè)對(duì)象進(jìn)行淺拷貝赛惩,相當(dāng)于對(duì)指向?qū)ο蟮闹羔樳M(jìn)行復(fù)制,產(chǎn)生一個(gè)新的指向這個(gè)對(duì)象的指針趁餐,那么就是有兩個(gè)指針指向同一個(gè)對(duì)象喷兼,這個(gè)對(duì)象銷毀后兩個(gè)指針都應(yīng)該置空。深拷貝是對(duì)一個(gè)對(duì)象進(jìn)行拷貝后雷,相當(dāng)于對(duì)對(duì)象進(jìn)行復(fù)制季惯,產(chǎn)生一個(gè)新的對(duì)象,那么就有兩個(gè)指針?lè)謩e指向兩個(gè)對(duì)象臀突。當(dāng)一個(gè)對(duì)象改變或者被銷毀后拷貝出來(lái)的新的對(duì)象不受影響勉抓。
? 實(shí)現(xiàn)深拷貝需要實(shí)現(xiàn)NSCoying協(xié)議,實(shí)現(xiàn)- (id)copyWithZone:(NSZone *)zone 方法候学。當(dāng)對(duì)一個(gè)property屬性含有copy修飾符的時(shí)候藕筋,在進(jìn)行賦值操作的時(shí)候?qū)嶋H上就是調(diào)用這個(gè)方法。
? 父類實(shí)現(xiàn)深拷貝之后梳码,子類只要重寫copyWithZone方法隐圾,在方法內(nèi)部調(diào)用父類的copyWithZone方法,之后實(shí)現(xiàn)自己的屬性的處理
? 父類沒(méi)有實(shí)現(xiàn)深拷貝掰茶,子類除了需要對(duì)自己的屬性進(jìn)行處理暇藏,還要對(duì)父類的屬性進(jìn)行處理。
2濒蒋、KVO盐碱,NSNotification,delegate及block的區(qū)別
- KVO就是cocoa框架實(shí)現(xiàn)的觀察者模式,一般同KVC搭配使用沪伙,通過(guò)KVO可以檢測(cè)到一個(gè)值的變化瓮顽,比如view的高度變化。是一對(duì)多的關(guān)系围橡,一個(gè)值變化會(huì)通知所有觀察者暖混。
- NSNotification是通知,也是一對(duì)多的場(chǎng)景某饰。在某些情況下儒恋,KVO和NSNotification是一樣的都是狀態(tài)變化后告知對(duì)方善绎。NSNotification的特點(diǎn)黔漂,就是需要被觀察者主動(dòng)發(fā)出通知,然后觀察者注冊(cè)監(jiān)聽(tīng)后再來(lái)進(jìn)行響應(yīng)禀酱,比KVO多了發(fā)送通知的一步炬守,但是其優(yōu)點(diǎn)就是監(jiān)聽(tīng)不局限于屬性的變化,還可以對(duì)多種多樣的狀態(tài)變化進(jìn)行監(jiān)聽(tīng)剂跟,監(jiān)聽(tīng)范圍廣减途,使用也靈活
- delegate是代理酣藻,就是我不想做的事情交給別人做。比如狗需要吃飯鳍置,就是通過(guò)delegate通知主人辽剧,主人就會(huì)給它做飯,盛飯税产,倒水怕轿,這些狗不需要關(guān)心,只需要調(diào)用delegate就可以了辟拷,又其它類完成所需要的操作撞羽。所有delegate是一對(duì)一關(guān)系
- block就是delegate的另一種形式,是函數(shù)式編程的一種形式衫冻。使用場(chǎng)景跟delegate一樣诀紊,相比delegate更加靈活,而且代理的實(shí)現(xiàn)更直觀
- KVO的使用場(chǎng)景是數(shù)據(jù)隅俘,需求是數(shù)據(jù)變化邻奠,比如股票價(jià)格變化,我們一般使用KVO(觀察者模式)为居。delegate一般使用場(chǎng)景是行為惕澎,需求是需要?jiǎng)e人幫我做一件事情,比如買賣股票颜骤,我們一般使用delegate
- Notification一般是進(jìn)行全局通知唧喉,比如好消息一出,通知大家去買忍抽。delegate是強(qiáng)關(guān)聯(lián)八孝,就是委托和代理雙方相互知道,你委托別人買股票你就需要知道經(jīng)紀(jì)人鸠项,經(jīng)紀(jì)人也不要知道自己的顧客干跛。Notification是弱關(guān)聯(lián),好消息發(fā)出祟绊,你不需要知道是誰(shuí)發(fā)的也可以做出相應(yīng)反應(yīng)楼入,同理發(fā)消息的人也不需要知道接受的人也可以正常發(fā)消息
3、將一個(gè)函數(shù)在主線程執(zhí)行的4種方法
? GCD方法牧抽,通過(guò)向主線程隊(duì)列發(fā)送一個(gè)block塊嘉熊,使block里的方法可以在主線程中執(zhí)行。
dispatch_async(dispatch_get_main_queue(),^{
需要執(zhí)行的方法
});
- NSOperation方法
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; // 主隊(duì)列
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
需要執(zhí)行的方法
}];
[mainQueue addOperation:operation];
- NSThread
[self performSelector:@selector(method) onThread [NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil];
[self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES];
[[NSThread mainThread] performSelector:@selector(method) withObject:nil];
- RunLoop方法
[[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil];
4扬舒、如何讓計(jì)時(shí)器調(diào)用一個(gè)類方法
? 計(jì)時(shí)器只能調(diào)用實(shí)例方法阐肤,但是可以在這個(gè)實(shí)例方法里面調(diào)用靜態(tài)方法。
? 使用計(jì)時(shí)器需要注意,計(jì)時(shí)器一定要加入RunLoop中孕惜,并且選好model才能運(yùn)行愧薛。scheduledTimerWithTimeInterval方法創(chuàng)建一個(gè)計(jì)時(shí)器并加入到RunLoop中所以可以直接使用。
? 如果計(jì)時(shí)器的repeats選擇YES說(shuō)明這個(gè)計(jì)時(shí)器會(huì)重復(fù)執(zhí)行衫画,一定要在合適的時(shí)機(jī)調(diào)用計(jì)時(shí)器的invalid毫炉。不能在dealloc中調(diào)用,因?yàn)橐坏┰O(shè)置為repeats 為yes削罩,計(jì)時(shí)器會(huì)強(qiáng)持有self碘箍,導(dǎo)致dealloc永遠(yuǎn)不會(huì)被調(diào)用,這個(gè)類就永遠(yuǎn)無(wú)法被釋放鲸郊。比如可以在viewDidDisappear中調(diào)用丰榴,這樣當(dāng)類需要被回收的時(shí)候就可以正常進(jìn)入dealloc中了。
[NSTimer scheduledTimerWithTimeInterval:1 target:self
selector:@selector(timerMethod) userInfo:nil repeats:YES];
-(void)timerMethod
{
調(diào)用類方法
[[self class] staticMethod];
}
-(void)invalid
{
[timer invalid];
timer =nil;
}
5秆撮、如何重寫類方法
1四濒、在子類中實(shí)現(xiàn)一個(gè)同基類名字一樣的靜態(tài)方法
2、在調(diào)用的時(shí)候不要使用類名調(diào)用职辨,而是使用[self
class]的方式調(diào)用盗蟆。原理,用類名調(diào)用是早綁定舒裤,在編譯期綁定喳资,用[self class]是晚綁定,在運(yùn)行時(shí)決定調(diào)用哪個(gè)方法
6腾供、iOS 核心框架
? CoreAnimation
? CoreGraphics
? CoreLocation
? AVFoundation
? Foundation
7仆邓、iOS本地?cái)?shù)據(jù)存儲(chǔ)都有幾種方式?
①.NSkeyedArchiver:采用歸檔的形式來(lái)保存數(shù)據(jù),該數(shù)據(jù)對(duì)象需要遵守NSCoding協(xié)議,并且該對(duì)象對(duì)應(yīng)的類必須提供encodeWithCoder:和initWithCoder:方法.前一個(gè)方法告訴系統(tǒng)怎么對(duì)對(duì)象進(jìn)行編碼,而后一個(gè)方法則是告訴系統(tǒng)怎么對(duì)對(duì)象進(jìn)行解碼.
②.NSUserDefaults:用來(lái)保存應(yīng)用程序設(shè)置和屬性,用戶保存的數(shù)據(jù).用戶再次打開(kāi)程序或者開(kāi)機(jī)后這些數(shù)據(jù)仍然存在.NSUserDefaults可以存儲(chǔ)的數(shù)據(jù)類型包括:NSData,NSString,NSNumber,NSDate,NSArray.NSDictionary,其他類型的數(shù)據(jù)需要先行轉(zhuǎn)換.
③.Write寫入方式:永久保存在磁盤中.具體:a.獲得文件保存的路徑.b.生成該路徑下的文件,c,往文件中寫入數(shù)據(jù).d.從文件中讀出數(shù)據(jù).
④.SQLite:采用SQLite數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)數(shù)據(jù),SQLite作為一種輕量級(jí)數(shù)據(jù)庫(kù).具體:a.添加SQLite相關(guān)的庫(kù)以及頭文件,b.使用數(shù)據(jù)庫(kù)存數(shù)數(shù)據(jù):打開(kāi)數(shù)據(jù)庫(kù),編寫數(shù)據(jù)庫(kù)語(yǔ)句,執(zhí)行,關(guān)閉數(shù)據(jù)庫(kù).另:寫入數(shù)據(jù)庫(kù),字符串可以采用char方式,而從數(shù)據(jù)庫(kù)中取出char類型,當(dāng)char類型有表示中文字符時(shí),會(huì)出現(xiàn)亂碼,這是因?yàn)閿?shù)據(jù)庫(kù)默認(rèn)使用ascII編碼方式,所以想要正確從數(shù)據(jù)庫(kù)中取出中文,需要使用NSString來(lái)接受從數(shù)據(jù)庫(kù)取出的字符串.
⑤.CoreData:原理是對(duì)SQLite的封裝,開(kāi)發(fā)者不需要接觸sql語(yǔ)句,就可以對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作.
8、什么是安全釋放?
先釋放再置空.
9伴鳖、什么是序列化和反序列化,可以用來(lái)做什么?如何在OC中實(shí)現(xiàn)復(fù)雜對(duì)象的存儲(chǔ).
序列化和反序列化:歸檔和反歸檔,進(jìn)行本地化,進(jìn)行數(shù)據(jù)存儲(chǔ).
CoreData:數(shù)據(jù)托管.有四種存儲(chǔ)方式:xml,sqlite,二進(jìn)制,內(nèi)存.
遵循NSCoding協(xié)議之后,進(jìn)行歸檔即可實(shí)現(xiàn)復(fù)雜對(duì)象的存儲(chǔ).
10节值、事件循環(huán),是線程里面的一個(gè)組件.主線程的RunLoop是自動(dòng)開(kāi)啟的.分為:計(jì)時(shí)源(timer source),事件源(輸入源):input source.防止CPU中斷(保證程序執(zhí)行的線程不會(huì)被系統(tǒng)終止).
Runloop提供了一種異步執(zhí)行代碼的機(jī)制,并不能并行執(zhí)行任務(wù),是事件接收和分發(fā)機(jī)制的一個(gè)實(shí)現(xiàn).每一個(gè)線程都有其對(duì)應(yīng)的RunLoop,但是默認(rèn)非主線程的RunLoop是沒(méi)有運(yùn)行的,需要為RunLoop添加至少一個(gè)事件源,然后run它.
一般情況下我們是沒(méi)有必要去啟動(dòng)線程的RunLoop的,除非你在一個(gè)單獨(dú)的線程中需要長(zhǎng)時(shí)間的檢測(cè)某個(gè)事件.
RunLoop,正如其名所示,是線程進(jìn)入和被線程用來(lái)響應(yīng)事件以及調(diào)用事件處理函數(shù)的地方.
input source傳遞異步事件,通常是來(lái)自其他線程和不同程序的消息。
timer source傳遞同步事件.
當(dāng)有事件發(fā)生時(shí),RunLoop會(huì)根據(jù)具體的事件類型通知應(yīng)用程序作出響應(yīng).
當(dāng)沒(méi)有事件發(fā)生時(shí),RunLoop會(huì)進(jìn)入休眠狀態(tài),從而到達(dá)省電的目的.
當(dāng)事件再次發(fā)生時(shí),RunLoop會(huì)被重新喚醒,處理事件.
一般在開(kāi)發(fā)中很少會(huì)主動(dòng)創(chuàng)建RunLoop,而通常會(huì)把事件添加到RunLoop中.
11榜聂、ViewController的didReceiveMemoryWarning是在什么時(shí)候被調(diào)用的?
1.當(dāng)應(yīng)用程序的內(nèi)存使用接近系統(tǒng)的最大內(nèi)存使用時(shí),應(yīng)用會(huì)向系統(tǒng)發(fā)送內(nèi)存警告,這時(shí)候系統(tǒng)會(huì)調(diào)用方法向所有ViewController發(fā)送內(nèi)存警告.
2.打開(kāi)系統(tǒng)相機(jī).
3.加載高清圖片.
默認(rèn)操作:把里面沒(méi)有用的對(duì)象進(jìn)行釋放.
12搞疗、事件響應(yīng)者鏈
如果當(dāng)前view是控制器的view,那么就傳遞給控制器
如果控制器不存在须肆,則將其傳遞給它的父控件
在視圖層次結(jié)構(gòu)的最頂層視圖也不能處理接收到的事件或消息匿乃,則將事件或消息傳遞給UIWindow對(duì)象進(jìn)行處理
如果UIWindow對(duì)象也不處理,則將事件或消息傳遞給UIApplication對(duì)象
如果UIApplication也不能處理該事件或消息豌汇,則將其丟棄
補(bǔ)充:如何判斷上一個(gè)響應(yīng)者
如果當(dāng)前這個(gè)view是控制器的view幢炸,那么控制器就是上一個(gè)響應(yīng)者
如果當(dāng)前這個(gè)view不是控制器的view,那么父控件就是上一個(gè)響應(yīng)者
13瘤礁、觸摸事件的傳遞
觸摸事件的傳遞是從父控件傳遞到子控件
如果父控件不能接收觸摸事件阳懂,那么子控件就不可能接收到觸摸事件
不能接受觸摸事件的四種情況
不接收用戶交互梅尤,即:userInteractionEnabled = NO
隱藏柜思,即:hidden = YES
透明岩调,即:alpha <= 0.01
未啟用,即:enabled = NO
提示:UIImageView的userInteractionEnabled默認(rèn)就是NO赡盘,因此UIImageView以及它的子控件默認(rèn)是不能接收觸摸事件的
如何找到最合適處理事件的控件:
首先号枕,判斷自己能否接收觸摸事件
§ 可以通過(guò)重寫hitTest:withEvent:方法驗(yàn)證
其次,判斷觸摸點(diǎn)是否在自己身上
§ 對(duì)應(yīng)方法pointInside:withEvent:
從后往前(先遍歷最后添加的子控件)遍歷子控件陨享,重復(fù)前面的兩個(gè)步驟
如果沒(méi)有符合條件的子控件葱淳,那么就自己處理
14、UIScrollView的contentSize能否在viewDidLoad中設(shè)置抛姑?
能
- 因?yàn)閁IScrollView的內(nèi)容尺寸是根據(jù)其內(nèi)部的內(nèi)容來(lái)決定的赞厕,所以是可以在viewDidLoad中設(shè)置的
補(bǔ)充:(這僅僅是一種特殊情況) - 前提,控制器B是控制器A的一個(gè)子控制器定硝,且控制器B的內(nèi)容只在控制器A的view的部分區(qū)域中顯示
假設(shè)控制器B的view中有一個(gè)UIScrollView這樣一個(gè)子控件 - 如果此時(shí)在控制器B的viewDidLoad中設(shè)置UIScrollView的contentSize的話會(huì)導(dǎo)致不準(zhǔn)確的問(wèn)題
- 因?yàn)槿魏慰刂破鞯膙iew在viewDidLoad的時(shí)候的尺寸都是不準(zhǔn)確的皿桑,如果有子控件的尺寸依賴父控件的尺寸,在這個(gè)方法中設(shè)置會(huì)導(dǎo)致子控件的frame不準(zhǔn)確蔬啡,所以這時(shí)應(yīng)該在下面的方法中設(shè)置子控件的尺寸
15诲侮、描述下SDWebImage里面給UIImageView加載圖片的邏輯
SDWebImage 中為UIImageView 提供了一個(gè)分類UIImageView+WebCache.h, 這個(gè)分類中有一個(gè)最常用的接口sd_setImageWithURL:placeholderImage:,會(huì)在真實(shí)圖片出現(xiàn)前會(huì)先顯示占位圖片箱蟆,當(dāng)真實(shí)圖片被加載出來(lái)后在替換占位圖片
? 加載圖片的過(guò)程大致如下:
○ 首先會(huì)在SDWebImageCache 中尋找圖片是否有對(duì)應(yīng)的緩存, 它會(huì)以u(píng)rl
作為數(shù)據(jù)的索引先在內(nèi)存中尋找是否有對(duì)應(yīng)的緩存
○ 如果緩存未找到就會(huì)利用通過(guò)MD5處理過(guò)的key來(lái)繼續(xù)在磁盤中查詢對(duì)應(yīng)的數(shù)據(jù), 如果找到了, 就會(huì)把磁盤中的數(shù)據(jù)加載到內(nèi)存中沟绪,并將圖片顯示出來(lái)
○ 如果在內(nèi)存和磁盤緩存中都沒(méi)有找到,就會(huì)向遠(yuǎn)程服務(wù)器發(fā)送請(qǐng)求空猜,開(kāi)始下載圖片
○ 下載后的圖片會(huì)加入緩存中绽慈,并寫入磁盤中
○ 整個(gè)獲取圖片的過(guò)程都是在子線程中執(zhí)行,獲取到圖片后回到主線程將圖片顯示出來(lái)