作者:戀空k
1.交互兩個方法的現(xiàn)實有什么風(fēng)險?
2.方法簽名有什么作用甜孤?
3.id和NSObject ,instancetype的區(qū)別吞获?
類方法中,以alloc或new開頭
實例方法中娘赴,以autorelease规哲,init,retain或self開頭會返回一個方法所在類類型的對象诽表,這些方法就被稱為是關(guān)聯(lián)返回類型的方法唉锌。換句話說,這些方法的返回結(jié)果以方法所在的類為類型竿奏。
非關(guān)聯(lián)返回類型 + (id)constructAnArray; 根據(jù)Cocoa的方法命名規(guī)范袄简,得到的返回類型就和方法聲明的返回類型一樣,是id泛啸。
- (instancetype)constructAnArray; 得到的返回類型和方法所在類的類型相同绿语,是NSArray*!總結(jié)一下,instancetype的作用,就是使那些非關(guān)聯(lián)返回類型的方法返回所在類的類型吕粹!
instancetype和id區(qū)別 :
1.id在編譯的時候不能判斷對象的真實類型instancetype在編譯的時候可以判斷對象的真實類型
2.如果init方法的返回值是instancetype,那么將返回值賦值給一個其它的對象會報一個警告如果是在以前, init的返回值是id,那么將init返回的對象地址賦值給其它對象是不會報錯的
3.id可以用來定義變量, 可以作為返回值, 可以作為形參instancetype只能用于作為返回值
//err,expected a type - (void)setValue:(instancetype)value { //do something } 就是錯的种柑,應(yīng)該寫成:- (void)setValue:(id)value { //d
注意:以后但凡自定義構(gòu)造方法, 返回值盡量使用instancetype, 不要使用id
總結(jié)一下,instancetype的作用匹耕,就是使那些非關(guān)聯(lián)返回類型的方法返回所在類的類型聚请!
一、關(guān)聯(lián)返回類型(related result types)根據(jù)Cocoa的命名規(guī)則泌神,滿足下述規(guī)則的方法:1良漱、類方法中舞虱,以alloc或new開頭2欢际、實例方法中,以autorelease矾兜,init损趋,retain或self開頭會返回一個方法所在類類型的對象,這些方法就被稱為是關(guān)聯(lián)返回類型的方法椅寺。換句話說浑槽,這些方法的返回結(jié)果以方法所在的類為類型,說的有點繞口返帕,請看下面的例子:
@interface NSObject
+ (id)alloc;
- (id)init;
@end
@interface NSArray : NSObject
@end
當(dāng)我們使用如下方式初始化NSArray時:NSArray *array = [[NSArray alloc] init];
照Cocoa的命名規(guī)則桐玻,語句[NSArray alloc] 的類型就是NSArray因為alloc的返回類型屬于關(guān)聯(lián)返回類型。同樣荆萤,[[NSArray alloc]init] 的返回結(jié)果也是NSArray镊靴。
1.NSObject包含了一些其他的方法,需要實現(xiàn)NSObject協(xié)議链韭,可以用NSObject來表示id偏竟,但是不能用id來表示NSObject
3.id可以是任何對象,包括不是NSObject的對象
4.定義id的時候不需要*敞峭,而定義NSOject的時候需要踊谋。
第一種是最常用的,id是個指針旋讹,任意類型的指針殖蚕。它簡單地申明了指向?qū)ο蟮闹羔槪瑳]有給編譯器任何類型信息
第二種表示使用NSObject靜態(tài)類型不是所有的Foundation/Cocoa對象都繼承息NSObject沉迹,比如NSProxy就不從NSObject繼承嫌褪,所以你無法使用NSObject*指向這個對象,即使NSProxy對象有release和retain這樣的通用方法胚股。為了解決這個問題笼痛,你需要第3種定義
第三種: id<NSObject>告訴編譯器,你不關(guān)心對象是什么類型,但它必須遵守NSObject協(xié)議(protocol)缨伊,編譯器就能保證所有賦值給id<NSObject>類型的對象都遵守NSObject協(xié)議(protocol)摘刑。所以你無法使用NSObject*指向這個對象,即使NSProxy對象有release和retain這樣的通用方法
總結(jié): 1刻坊、如果你不需要任何的類型檢查枷恕,使用id,它經(jīng)常作為返回類型谭胚,也經(jīng)常用于申明代理(delegate)類型徐块。 2、如果真的需要編譯器檢查灾而,那你就考慮使用第2種或者第3種胡控。 3、第三種使用協(xié)議(protocol)的優(yōu)點是旁趟,它能指向NSProxy對象昼激,而更常用的情況是,你只想知道某個對象遵守了哪個協(xié)議锡搜,而不用關(guān)心它是什么類型橙困。
作為一個開發(fā)者,有一個學(xué)習(xí)的氛圍跟一個交流圈子特別重要耕餐,這是一個我的iOS交流群:761407670 進群密碼123凡傅,不管你是小白還是大牛歡迎入駐 ,分享BAT,阿里面試題肠缔、面試經(jīng)驗夏跷,討論技術(shù), 大家一起交流學(xué)習(xí)成長桩砰!
另附上一份各好友收集的大廠面試題拓春,進群可自行下載!
4.使用kvo什么時候移除監(jiān)聽(dealloc不能移除的情況)亚隅?
一般KVO奔潰的原因:
被觀察的對象銷毀掉了(被觀察的對象是一個局部變量)
觀察者被釋放掉了,但是沒有移除監(jiān)聽(如模態(tài)推出,push,pop等)
注冊的監(jiān)聽沒有移除掉,又重新注冊了一遍監(jiān)聽
觸發(fā)回調(diào)方法(這兒需要注意一點,在Person.m文件中如果賦值沒有通過setter方法或者是kvc,例如(_name = name)這個時候不會觸發(fā)kvc的回調(diào)方法,也就是說賦值必須得通過setter方法或者KVC賦值,才會觸發(fā)回調(diào)方法)
當(dāng)觀察者不需要監(jiān)聽時硼莽,可以調(diào)用removeObserver:forKeyPath:方法將KVO移除。需要注意的是煮纵,調(diào)用removeObserver需要在觀察者消失之前懂鸵,否則會導(dǎo)致Crash。
直接修改成員變量會觸發(fā)KVO么行疏?不會觸發(fā)KVO因為匆光,觸發(fā)KVO是因為,執(zhí)行set方法時候酿联,調(diào)用 willChangeValueForKey didChangeValueForKey 但是直接修改成員變量不會調(diào)用set方法
5.block里面會不會存在self為空的情況(weak strong的原理)终息?
1.block 內(nèi)部創(chuàng)建的強引用夺巩,block 是不會持有它的,block 只持有外部的強應(yīng)用
值得注意的是周崭,在ARC下__block會導(dǎo)致對象被retain柳譬,有可能導(dǎo)致循環(huán)引用。而在MRC下续镇,則不會retain這個對象美澳,也不會導(dǎo)致循環(huán)引用
如果是在MRC模式下,使用__block修飾self,則此時block訪問被釋放的self摸航,則會導(dǎo)致crash制跟。
在MRC環(huán)境下,__block根本不會對指針?biāo)赶虻膶ο髨?zhí)行copy操作酱虎,而只是把指針進行的復(fù)制雨膨。而這一點往往是很多新手&老手所不知道的!
而在ARC環(huán)境下逢净,對于聲明為__block的外部對象哥放,在block內(nèi)部會進行retain歼指,以至于在block環(huán)境內(nèi)能安全的引用外部對象爹土,所以要謹(jǐn)防循環(huán)引用的問題!
- (void)testBlockRetainCycle { ClassA* objA = [[ClassA alloc] init];
__weak typeof(objA) weakObjA = objA; s
elf.myBlock = ^() {
__strong typeof(weakObjA) strongWeakObjA = weakObjA;
[strongWeakObjA doSomething]; };
objA.objA = self; }
注:此方法只能保證在block執(zhí)行期間對象不被釋放踩身,如果對象在block執(zhí)行執(zhí)行之前已經(jīng)被釋放了胀茵,該方法也無效。
6.什么是動態(tài)連接庫挟阻?
7.NSNull和nil的區(qū)別琼娘?
nil:指向一個對象的空指針 Nil:指向一個類的空指針,
NULL:指向其他類型(如:基本類型、C類型)的空指針, 用于對非對象指針賦空值.
NSNull:在集合對象中附鸽,表示空值的對象.
NSNull在Objective-C中是一個類 .NSNull有 + (NSNull *)null; 單例方法.多用于集合(NSArray,NSDictionary)中值為空的對象.
NSArray *array = [NSArray arrayWithObjects: [[NSObject alloc] init], [NSNull null], @"aaa", nil, [[NSObject alloc] init], [[NSObject alloc] init], nil];NSLog(@"%ld", array.count);// 輸出 3脱拼,NSArray以nil結(jié)尾
8.Objective-C類能動態(tài)添加成員變量嗎?
不能坷备。
因此一并討論熄浓。很多人在學(xué)到Category時都會有疑問,既然允許用Category給類增加方法和屬性省撑,那為什么不允許增加成員變量赌蔑?
在Objective-C提供的runtime函數(shù)中,確實有一個class_addIvar()函數(shù)用于給類添加成員變量竟秫,但是文檔中特別說明:This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.
意思是說娃惯,這個函數(shù)只能在“構(gòu)建一個類的過程中”調(diào)用。一旦完成類定義肥败,就不能再添加成員變量了趾浅。經(jīng)過編譯的類在程序啟動后就被runtime加載愕提,沒有機會調(diào)用addIvar。程序在運行時動態(tài)構(gòu)建的類需要在調(diào)用objc_registerClassPair之后才可以被使用皿哨,同樣沒有機會再添加成員變量揪荣。
顯然,這樣做會帶來嚴(yán)重問題往史,為基類動態(tài)增加成員變量會導(dǎo)致所有已創(chuàng)建出的子類實例都無法使用仗颈。那為什么runtime允許動態(tài)添加方法和屬性,而不會引發(fā)問題呢椎例?
因為方法和屬性并不“屬于”類實例挨决,而成員變量“屬于”類實例。我們所說的“類實例”概念订歪,指的是一塊內(nèi)存區(qū)域脖祈,包含了isa指針和所有的成員變量。所以假如允許動態(tài)修改類成員變量布局刷晋,已經(jīng)創(chuàng)建出的類實例就不符合類定義了盖高,變成了無效對象。但方法定義是在objc_class中管理的眼虱,不管如何增刪類方法喻奥,都不影響類實例的內(nèi)存布局,已經(jīng)創(chuàng)建出的類實例仍然可正常使用捏悬。