1. 為什么說Objective-C是一門動態(tài)的語言荸百?
object-c類的類型和數(shù)據(jù)變量的類型都是在運行是確定的竟坛,而不是在編譯時確定哪自。例如:多態(tài)特性灾测,我們可以使用父類對象來指向子類對象爆价,并且可以用來調(diào)用子類的方法。運行時(runtime)特性,我們可以動態(tài)的添加方法媳搪,或者替換方法
2. 講一下MVC和MVVM铭段,MVP?
http://blog.csdn.net/hudan2714/article/details/50990359
3. 為什么代理要用weak秦爆?代理的delegate和dataSource有什么區(qū)別序愚?block和代理的區(qū)別?
防止循環(huán)引用。例如View有一個協(xié)議等限,需要一個代理實現(xiàn)回調(diào)爸吮。一個Controller添加這個View芬膝,并且遵守協(xié)議,成為View的代理形娇。如果不用week锰霜,用strong,Controller ->View -> delegate -> Controller桐早,就循環(huán)引用了癣缅。
delegate偏重于與用戶交互的回調(diào),有那些方法可以供我使用哄酝,例如UITableviewDelegate友存;dataSource偏重于數(shù)據(jù)的回調(diào),view里面有什么東西炫七,屬性都是什么爬立,例如UITableviewDatasource;
代理 可讀性高 大部分可以屬性
block 寫的代碼少 一般作為參數(shù)
通知 占用資源
無論是block還是delegate模式本質(zhì)上都是回調(diào)万哪,使用block侠驯,其優(yōu)點是回調(diào)的block代碼塊直接就放在了block賦值的地方,使代碼更為緊湊奕巍,缺點是block內(nèi)使用到當(dāng)前類的實例變量的時候吟策,需要注意循環(huán)引用的問題,即需要使用__block(MRC下)或者__weak(ARC下)定義一個弱引用的self出來的止,block里面使用弱引用的self去操作屬性或調(diào)用方法檩坚。delegate模式不用像block一樣做特殊處理,但是如果多個對象設(shè)置的代理是同一個對象诅福,就需要在delegate方法中判斷當(dāng)前執(zhí)行代理的是哪個對象匾委。
Datasource和Delegate兩者的區(qū)別:
Datasource 是在告訴使用者之前的view中都有什么東西,有什么屬性啊氓润,屬性的值都是多少赂乐,是只關(guān)于數(shù)據(jù)的東西。
Delegate 是在告訴使用者之前的view有什么方法可以供我調(diào)用咖气。
一個是數(shù)據(jù)挨措,一個是操作.
block和代理的區(qū)別:
首先兩者作用是一樣的,都是進行單一回調(diào)崩溪。不同的是浅役,delegate是個對象,然后用過一個對象自己調(diào)用代理協(xié)議函數(shù)來完成整個流程伶唯。block是傳遞一個函數(shù)指針觉既,利用函數(shù)指針執(zhí)行來進行回調(diào)。還有在內(nèi)存管理上需要注意,delegate不需要保存引用瞪讼。block對引用數(shù)據(jù)有copy的處理
4. 屬性的實質(zhì)是什么岭参?包括哪幾個部分?屬性默認(rèn)的關(guān)鍵字都有哪些尝艘?@dynamic關(guān)鍵字和@synthesize關(guān)鍵字是用來做什么的?
屬性的組成: @property = ivar + getter + setter;
實例變量+get方法+set方法,也就是說使用@property 會自動生成setter和getter方法;
我們經(jīng)常使用assign,weak,strong,copy,nonatomic,atomic,readonly等關(guān)鍵字姿染,下面我們列個表格去歸納一下屬性關(guān)鍵字具體作用:
@dynamic告訴編譯器,屬性的setter與getter方法由用戶自己實現(xiàn)背亥。
@synthesize的語義是如果你沒有手動實現(xiàn)setter方法和getter方法,那么編譯器會自動為你加上這兩個方法悬赏。
5. 屬性的默認(rèn)關(guān)鍵字是什么狡汉?
對于基本數(shù)據(jù)類型默認(rèn)關(guān)鍵字是
atomic,readwrite,assign
對于普通的OC對象
atomic,readwrite,strong
6. NSString為什么要用copy關(guān)鍵字,如果用strong會有什么問題闽颇?(注意:這里沒有說用strong就一定不行盾戴。使用copy和strong是看情況而定的)
兩個都是屬性關(guān)鍵字。
??copy是內(nèi)容拷貝兵多,創(chuàng)建一個和原來的對象內(nèi)容相同的新對象尖啡,和原來的對象無關(guān)。
??strong是指針拷貝剩膘,對原來對象的引用衅斩,原來的對象引用計數(shù)加1。如果給它賦值的是一個可變數(shù)據(jù)怠褐,這個數(shù)據(jù)改變畏梆,那么該屬性也發(fā)生變化。
7. 如何令自己所寫的對象具有拷貝功能?
實現(xiàn)NSCoping協(xié)議奈懒。如果自定義的對象分為可變版本與不可變版本奠涌,那么就要同時實現(xiàn) NSCopying與NSMutableCopying協(xié)議
@protocol NSCopying
- (id)copyWithZone:(nullable NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
@end
8. ? 可變集合類 和 不可變集合類的 copy 和 mutablecopy有什么區(qū)別?如果是集合是內(nèi)容復(fù)制的話磷杏,集合里面的元素也是內(nèi)容復(fù)制么溜畅?
深淺復(fù)制http://www.reibang.com/p/ac07c26f467d
9.為什么IBOutlet修飾的UIView也適用weak關(guān)鍵字?
因為 Controller ->View ->subView,所以沒有必要Controller->subview了茴丰。
10. ? nonatomic和atomic的區(qū)別达皿?atomic是絕對的線程安全么?為什么贿肩?如果不是峦椰,那應(yīng)該如何實現(xiàn)?
nonatomic和atomic用來決定編譯器生成的getter和setter操作是否為原子操作汰规。
atomic不是絕對的線程安全汤功。atomic的本意是指屬性的存取方法是線程安全的,并不保證整個對象是線程安全的溜哮。如:
聲明一個NSMutableArray的原子屬性stuff滔金,此時self.stuff 和 self.stuff = otherstuff都是線程安全的色解。但是使用[self.stuff objectAtIndex:index]就不是線程安全的。需要用互斥鎖來保證線程安全性餐茵。
11. UICollectionView自定義layout如何實現(xiàn)科阎?
創(chuàng)建自定義UICollectionView layout
12. 用StoryBoard開發(fā)界面有什么弊端?如何避免忿族?
13. 進程和線程的區(qū)別锣笨?同步異步的區(qū)別?并行和并發(fā)的區(qū)別道批?
1.進程和線程的區(qū)別
線程和進程的區(qū)別主要在于它們是不同的操作系統(tǒng)資源管理方式错英。進程有獨立的地址空間,一個進程崩潰后隆豹,在保護模式的影響下不會對其他進程產(chǎn)生影響椭岩,而線程只是一個進程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量璃赡,但線程之間沒有單獨的地址空間判哥,一個線程死掉就等同于整個進程死掉,所以多進程的程序要比多線程的程序健壯鉴吹,但在進程切換時姨伟,耗費資源較大,效率要差一些豆励。但對于一些要求同時進行并且又要共享某些變量的并發(fā)操作夺荒,只能用線程,不能用進程良蒸。
??線程是CPU獨立運行和獨立調(diào)度的基本單位(可以理解為一個進程中執(zhí)行的代碼片段)技扼。
??進程是資源分配的基本單位(進程是一塊包含了某些資源的內(nèi)存區(qū)域)。
??進程和線程都是由操作系統(tǒng)所體會的程序運行的基本單元嫩痰,系統(tǒng)利用該基本單元實現(xiàn)系統(tǒng)對應(yīng)用的并發(fā)性剿吻。進程是線程的容器,真正完成代碼執(zhí)行的線程串纺,而進程則作為線程的執(zhí)行環(huán)境丽旅。一個程序至少包含一個進程,一個進程至少包含一個線程纺棺,一個進程中的所有線程共享當(dāng)前進程所擁有的資源榄笙。
2.同步異步的區(qū)別
異步和同步是相對的,同步就是順序執(zhí)行祷蝌,執(zhí)行完一個再執(zhí)行下一個茅撞,需要等待、協(xié)調(diào)運行。異步就是彼此獨立,在等待某事件的過程中繼續(xù)做自己的事米丘,不需要等待這一事件完成后再工作剑令。線程就是實現(xiàn)異步的一個方式。異步是讓調(diào)用方法的主線程不需要同步等待另一線程的完成拄查,從而可以讓主線程干其它的事情吁津。
??異步和多線程并不是一個同等關(guān)系,異步是最終目的,多線程只是我們實現(xiàn)異步的一種手段。異步是當(dāng)一個調(diào)用請求發(fā)送給被調(diào)用者,而調(diào)用者不用等待其結(jié)果的返回而可以做其它的事情堕扶。實現(xiàn)異步可以采用多線程技術(shù)或則交給另外的進程來處理腺毫。
3.并行和并發(fā)的區(qū)別
并發(fā)行和并行性的區(qū)別可以用饅頭做比喻。前者相當(dāng)于一個人同時吃三個饅頭和三個人同時吃一個饅頭挣柬。
??并發(fā)性(Concurrence):指兩個或兩個以上的事件或活動在同一時間間隔內(nèi)發(fā)生。并發(fā)的實質(zhì)是一個物理CPU(也可以多個物理CPU) 在若干道程序之間多路復(fù)用睛挚,并發(fā)性是對有限物理資源強制行使多用戶共享以提高效率邪蛔。
??并行性(parallelism)指兩個或兩個以上事件或活動在同一時刻發(fā)生。在多道程序環(huán)境下扎狱,并行性使多個程序同一時刻可在不同CPU上同時執(zhí)行侧到。
??區(qū)別:一個處理器同時處理多個任務(wù)和多個處理器或者是多核的處理器同時處理多個不同的任務(wù)。
??前者是邏輯上的同時發(fā)生(simultaneous)淤击,而后者是物理上的同時發(fā)生匠抗。
??兩者的聯(lián)系:并行的事件或活動一定是并發(fā)的,但反之并發(fā)的事件或活動未必是并行的污抬。并行性是并發(fā)性的特例汞贸,而并發(fā)性是并行性的擴展。
14. 線程間通信印机?
1.線程間通信簡介
所謂線程間的通信矢腻,就是一個線程操作完數(shù)據(jù)之后,另一個線程再去操作這組數(shù)據(jù)射赛。最常見的例子就是多柑,子線程下載數(shù)據(jù),主線程更新UI楣责。其實線程間的通信是非常普遍的竣灌, 只要你的App進行了數(shù)據(jù)請求就一定會發(fā)生。至于很多iOS程序員沒有發(fā)現(xiàn)秆麸,是因為幾乎所有網(wǎng)絡(luò)請求的框架的回調(diào)都是在主線程進行的初嘹,框架設(shè)計者都設(shè)計好了,所以你什么都不需要干蛔屹。
2.常見的通信方式
1.GCD
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//子線程請求數(shù)據(jù)
dispatch_async(dispatch_get_main_queue(), ^{
//主線程更新UI
});
});
2.NSObject
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);
3.NSOperation
[NSOperationQueue mainQueue] addOperationWithBlock:^{
//更新UI
}
3.多線程同時操作一個數(shù)據(jù)
春運的時候削樊,就剩下一張票了,100個人同時購買,怎么辦漫贞,難道每個人都能購買成功甸箱?肯定不是,只要一個人買了迅脐,其他人就不能買了芍殖,不然票的數(shù)量得出現(xiàn)負數(shù)。這就出現(xiàn)了強占資源谴蔑,多條線程同時操作一個數(shù)據(jù)豌骏。iOS多線程之2.NSThread的加鎖@synchronized。這篇文章給出了一種解決方式隐锭,其實還有很多窃躲,NSLock、信號量钦睡、NSConditionLock蒂窒、barrier。其實實現(xiàn)得方向都是一致的荞怒,就是只要有一條線程操作這個數(shù)據(jù)洒琢,其他線程就不能操作了,等這個線程操作完了才能繼續(xù)操作褐桌。
15. ? GCD的一些常用的函數(shù)衰抑?(group,barrier荧嵌,信號量呛踊,線程同步)
iOS開發(fā)系列--并行開發(fā)其實很容易 文章很長,但是把iOS并發(fā)的所有方式都介紹了一遍啦撮,值得多讀幾遍恋技。 淺談GCD中的信號量是信號量的實際應(yīng)用案例,與用group應(yīng)用中的坑逻族,沒讀之前蜻底,我都沒意識到。
16. 如何使用隊列來避免資源搶奪聘鳞?
.多線程同時操作一個數(shù)據(jù)
春運的時候薄辅,就剩下一張票了,100個人同時購買抠璃,怎么辦站楚,難道每個人都能購買成功?肯定不是搏嗡,只要一個人買了窿春,其他人就不能買了拉一,不然票的數(shù)量得出現(xiàn)負數(shù)。這就出現(xiàn)了強占資源旧乞,多條線程同時操作一個數(shù)據(jù)蔚润。iOS多線程之2.NSThread的加鎖@synchronized。這篇文章給出了一種解決方式尺栖,其實還有很多嫡纠,NSLock、信號量延赌、NSConditionLock除盏、barrier。其實實現(xiàn)得方向都是一致的挫以,就是只要有一條線程操作這個數(shù)據(jù)者蠕,其他線程就不能操作了,等這個線程操作完了才能繼續(xù)操作掐松。
17. ? 數(shù)據(jù)持久化的幾個方案(fmdb用沒用過)
iOS中幾種數(shù)據(jù)持久化方案:我要永遠地記住你蠢棱!
18. 說一下AppDelegate的幾個方法?從后臺到前臺調(diào)用了哪些方法甩栈?第一次啟動調(diào)用了哪些方法?從前臺到后臺調(diào)用了哪些方法糕再?
1.點擊App圖標(biāo)(App沒有在后臺運行)
1.didFinishLaunchingWithOptions
??2.applicationDidBecomeActive
2.從后臺到前臺
1.applicationWillEnterForeground
??2.applicationDidBecomeActive
3.從前臺到后臺
1.applicationWillResignActive
??2.applicationDidEnterBackground
4.通過URLScheme打開App
1.applicationWillEnterForeground
??2.- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
??3.applicationDidBecomeActive
19. NSCache優(yōu)于NSDictionary的幾點量没?
NSCache勝過NSDictionary之處在于,當(dāng)系統(tǒng)資源將要耗盡時突想,它可以自動刪減緩存殴蹄。如果采用普通的字典,那么就要自己編寫掛鉤猾担,在系統(tǒng)發(fā)出“低內(nèi)存”通知時手工刪減緩存袭灯。
NSCache并不會“拷貝”鍵,而是會“保留”它绑嘹。此行為用NSDictionary也可以實現(xiàn)稽荧,然而需要編寫相當(dāng)復(fù)雜的代碼。NSCache對象不拷貝鍵的原因在于:很多時候工腋,鍵都是不支持拷貝操作的對象來充當(dāng)?shù)囊陶伞R虼耍琋SCache不會自動拷貝鍵擅腰,所以說蟋恬,在鍵不支持拷貝操作的情況下味悄,該類用起來比字典更方便啸驯。另外潜叛,NSCache是線程安全的,而NSDictionary則絕對不具備此優(yōu)勢星持。
20. 知不知道Designated Initializer?使用它的時候有什么需要注意的問題犁柜?
正確編寫Designated Initializer的幾個原則
21. 實現(xiàn)description方法能取到什么效果川梅?
22. objc使用什么機制管理對象內(nèi)存?
Block
block的實質(zhì)是什么洒沦?一共有幾種block豹绪?都是什么情況下生成的?
A:block對象就是一個結(jié)構(gòu)體申眼,里面有isa指針指向自己的類(global malloc stack)瞒津,有desc結(jié)構(gòu)體描述block的信息,__forwarding指向自己或堆上自己的地址括尸,如果block對象截獲變量巷蚪,這些變量也會出現(xiàn)在block結(jié)構(gòu)體中。最重要的block結(jié)構(gòu)體有一個函數(shù)指針濒翻,指向block代碼塊屁柏。block結(jié)構(gòu)體的構(gòu)造函數(shù)的參數(shù),包括函數(shù)指針有送,描述block的結(jié)構(gòu)體淌喻,自動截獲的變量(全局變量不用截獲),引用到的__block變量雀摘。(__block對象也會轉(zhuǎn)變成結(jié)構(gòu)體)
block代碼塊在編譯的時候會生成一個函數(shù)裸删,函數(shù)第一個參數(shù)是前面說到的block對象結(jié)構(gòu)體指針。執(zhí)行block阵赠,相當(dāng)于執(zhí)行block里面__forwarding里面的函數(shù)指針涯塔。
為什么在默認(rèn)情況下無法修改被block捕獲的變量? __block都做了什么清蚀?
A:在block中訪問的外部變量是復(fù)制過去的匕荸,寫操作不對原變量生效。
模擬一下循環(huán)引用的一個情況枷邪?block實現(xiàn)界面反向傳值如何實現(xiàn)榛搔?
A:兩個.h文件互相import了對方造成循環(huán)引用。block先聲明(在要傳值的controller里聲明
typedef void(^MyBlock)(NSString *name);//block的重命名
@property (nonatomic,copy) MyBlock block;//block的聲明)东揣,在準(zhǔn)備接收值的頁面里實現(xiàn)block药薯,
secondVC.block = ^void(NSString *name)
{
_label.text = name;
};,誰要傳值就在誰那里調(diào)用self.block(@"lalala");救斑。
iOS事件傳遞響應(yīng)鏈?zhǔn)鞘裁矗?/h2>
A:當(dāng)我們在使用微信等工具童本,點擊掃一掃,就能打開二維碼掃描視圖脸候。在我們點擊屏幕的時候,iphone OS獲取到了用戶進行了“單擊”這一行為俐镐,操作系統(tǒng)把包含這些點擊事件的信息包裝成UITouch和UIEvent形式的實例茵汰,然后找到當(dāng)前運行的程序皮迟,逐級尋找能夠響應(yīng)這個事件的對象,直到?jīng)]有響應(yīng)者響應(yīng)吱韭。這一尋找的過程速勇,被稱作事件的響應(yīng)鏈陨晶。
不同的響應(yīng)者以鏈?zhǔn)椒绞綄ふ遥珹ppDelegate->UIApplication->UIWindow->UIViewController->UIView->UIButton帝璧。
Runtime
objc在向一個對象發(fā)送消息時先誉,發(fā)生了什么?
Objc Runtime使得C具有了面向?qū)ο竽芰Φ乃福诔绦蜻\行時創(chuàng)建褐耳,檢查,修改類渴庆、對象和它們的方法铃芦,可以使用runtime的一系列方法實現(xiàn)。
附上OC中一個類的底層數(shù)據(jù)結(jié)構(gòu):
mac電腦上的路徑/usr/include/objc/runtime.h
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY; //isa指針指向Meta Class襟雷,因為Objc的類的本身也是一個Object刃滓,為了處理這個關(guān)系,r untime就創(chuàng)造了Meta Class耸弄,當(dāng)給類發(fā)送[NSObject alloc]這樣消息時咧虎,實際上是把這個消息發(fā)給了Class Object
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父類
const char *name OBJC2_UNAVAILABLE; // 類名
long version OBJC2_UNAVAILABLE; // 類的版本信息,默認(rèn)為0
long info OBJC2_UNAVAILABLE; // 類信息计呈,供運行期使用的一些位標(biāo)識
long instance_size OBJC2_UNAVAILABLE; // 該類的實例變量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變量鏈表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定義的鏈表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法緩存老客,對象接到一個消息會根據(jù)isa指針查找消息對象僚饭,這時會在method Lists中遍歷,如果cache了胧砰,常用的方法調(diào)用時就能夠提高調(diào)用的效率鳍鸵。
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;
OC中一個類的對象實例的數(shù)據(jù)結(jié)構(gòu)(/usr/include/objc/objc.h)
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
就是定義了一個向object發(fā)送消息時,Runtime庫會根據(jù)object的isa指針找到這個實例object所屬于的類尉间,然后在類的方法列表以及父類方法列表尋找對應(yīng)的方法運行偿乖。id是一個objc_object結(jié)構(gòu)類型的指針,這個類型的對象能夠轉(zhuǎn)換成任何一種對象哲嘲。
消息發(fā)送函數(shù):objc_msgSend
objc_msgSend()是[obj foo]的具體實現(xiàn);
在runtime中贪薪,objc_msgSend()是一個c函數(shù),[obj foo]會被翻譯成這樣的形式objc_msgSend(obj, foo)眠副。
去obj的對應(yīng)的類中找方法
先找緩存画切,找不到再去找方法列表
再找父類,如此向上傳遞
最后再找不到就要轉(zhuǎn)發(fā)
什么時候會報unrecognized selector錯誤囱怕?iOS有哪些機制來避免走到這一步霍弹?
http://www.reibang.com/p/4d40ff407d0e
能否向編譯后得到的類中增加實例變量?能否向運行時創(chuàng)建的類中添加實例變量娃弓?為什么典格?
不能向編譯后得到的類中增加實例變量;
能向運行時創(chuàng)建的類中添加實例變量台丛;
原因如下:
因為編譯后的類已經(jīng)注冊在 runtime 中耍缴,類結(jié)構(gòu)體中的 objc_ivar_list 實例變量的鏈表 和 instance_size 實例變量的內(nèi)存大小已經(jīng)確定,同時runtime 會調(diào)用 class_setIvarLayout 或 class_setWeakIvarLayout 來處理 strong weak 引用挽霉。所以不能向存在的類中添加實例變量防嗡;
運行時創(chuàng)建的類是可以添加實例變量,調(diào)用 class_addIvar 函數(shù)侠坎。但是得在調(diào)用 objc_allocateClassPair 之后蚁趁,objc_registerClassPair 之前,原因同上硅蹦。
runtime如何實現(xiàn)weak變量的自動置nil荣德?
runtime 對注冊的類闷煤, 會進行布局童芹,對于 weak 對象會放入一個 hash 表中。 用 weak 指向的對象內(nèi)存地址作為 key鲤拿,當(dāng)此對象的引用計數(shù)為0的時候會 dealloc假褪, 在這個 weak 表中搜索,找到所有以a為鍵的 weak 對象近顷,從而設(shè)置為 nil生音。
weak 修飾的指針默認(rèn)值是 nil (在Objective-C中向nil發(fā)送消息是安全的)
給類添加一個屬性后宁否,在類結(jié)構(gòu)體里哪些元素會發(fā)生變化?
class object/metaclass
咱們先看一下結(jié)構(gòu)體objc_class的定義
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
創(chuàng)建一個類屬性很簡單缀遍,主要有以下幾個步驟:
使用@property (class)來聲明一個類屬性慕匠;
為類屬性創(chuàng)建一個存儲變量,通常為全局變量域醇;
實現(xiàn)類屬性的getter與setter方法台谊,如果是只讀屬性,只需要實現(xiàn)getter方法譬挚。
類相當(dāng)于一個對象, 當(dāng)對象執(zhí)行這個方法即會發(fā)送一條消息, 之后根據(jù)isa指針查找消息對象锅铅,這時會在methodLists中遍歷,如果cache了减宣,常用的方法調(diào)用時就能夠提高調(diào)用的效率盐须。
RunLoop
1.runloop是來做什么的?runloop和線程有什么關(guān)系漆腌?主線程默認(rèn)開啟了runloop么贼邓?子線程呢?
2.runloop的mode是用來做什么的立帖?有幾種mode?
model 主要是用來指定事件在運行循環(huán)中的優(yōu)先級的悠砚,分為:
NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默認(rèn)晓勇,空閑狀態(tài)
UITrackingRunLoopMode:ScrollView滑動時
UIInitializationRunLoopMode:啟動時
NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
蘋果公開提供的 Mode 有兩個:
NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
NSRunLoopCommonModes(kCFRunLoopCommonModes)
3.為什么把NSTimer對象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主運行循環(huán)以后,滑動scrollview的時候NSTimer卻不動了灌旧?
RunLoop只能運行在一種mode下绑咱,如果要換mode,當(dāng)前的loop也需要停下重啟成新的枢泰。利用這個機制描融,ScrollView滾動過程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode會切換到UITrackingRunLoopMode來保證ScrollView的流暢滑動:只能在NSDefaultRunLoopMode模式下處理的事件會影響ScrollView的滑動。
如果我們把一個NSTimer對象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主運行循環(huán)中的時候, ScrollView滾動過程中會因為mode的切換衡蚂,而導(dǎo)致NSTimer將不再被調(diào)度窿克。
同時因為mode還是可定制的,所以:
Timer計時會被scrollView的滑動影響的問題可以通過將timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)來解決毛甲。代碼如下:
// http://weibo.com/luohanchenyilong/ (微博@iOS程序犭袁)
// https://github.com/ChenYilong
//將timer添加到NSDefaultRunLoopMode中
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerTick:)
userInfo:nil
repeats:YES];
//然后再添加到NSRunLoopCommonModes里
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(timerTick:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
4. 蘋果是如何實現(xiàn)Autorelease Pool的年叮?
autoreleasepool 以一個隊列數(shù)組的形式實現(xiàn),主要通過下列三個函數(shù)完成.
objc_autoreleasepoolPush
objc_autoreleasepoolPop
objc_autorelease
看函數(shù)名就可以知道,對 autorelease 分別執(zhí)行 push玻募,和 pop 操作只损。銷毀對象時執(zhí)行release操作。
類結(jié)構(gòu)
1.isa指針?(對象的isa跃惫,類對象的isa叮叹,元類的isa都要說)
Objective-C 是一門面向?qū)ο蟮木幊陶Z言。每一個對象都是一個類的實例爆存。在objective-c語言的內(nèi)部蛉顽,每一個對象都有一個名為 isa 的指針,指向該對象的類先较。每一個類描述了一系列它的實例的特點蜂林,包括成員變量的列表,成員函數(shù)的列表等拇泣。每一個對象都可以接受消息噪叙,而對象能夠接收的消息列表是保存在它所對應(yīng)的類中。
iOS class深入理解: 實例對象霉翔、類對象睁蕾、元類和isa指針
2.類方法(class method)和實例方法(instance method)有什么區(qū)別?
類方法债朵,也稱靜態(tài)方法子眶,指的是用static關(guān)鍵字修飾的方法。此方法屬類本身的方法序芦,不屬于類的某一個實例(對象)臭杰。類方法中不可直接使用實例變量。其調(diào)用方式有三種:可直接調(diào)用谚中、類名.方法名渴杆、對象名.方法名。實例方法指的是不用static關(guān)鍵字修飾的方法宪塔。每個實例對象都有自身的實例方法磁奖,互相獨立,不共享一個某筐。其調(diào)用方式只能是對象名.方法名比搭。
instance method 以減號 "-" 開頭
class method 以加號 “+” 開頭,相當(dāng)于static方法
區(qū)別:
靜態(tài)方法在程序開始時生成內(nèi)存,實例方法在程序運行中生成內(nèi)存南誊,
所以靜態(tài)方法可以直接調(diào)用,實例方法要先成生實例,通過實例調(diào)用方法身诺,靜態(tài)速度很快,但是多了會占內(nèi)存抄囚。
靜態(tài)內(nèi)存是連續(xù)的,因為是在程序開始時就生成了,而實例申請的是離散的空間,所以當(dāng)然沒有靜態(tài)方法快霉赡,
而且靜態(tài)內(nèi)存是有限制的,太多了程序會啟動不了怠苔。
使用場景:
如果需要訪問或者修改某個實例的成員變量時同廉,將該方法定義成實例方法仪糖。
類方法正好相反柑司,它不需要訪問或者修改某個實例的成員變量迫肖。
類方法一般用于實現(xiàn)一些工具方法,比如對某個對象進行擴展攒驰,或者實現(xiàn)單例蟆湖。
類方法常駐內(nèi)存,實例方法不是玻粪,所以類方法效率高但占內(nèi)存隅津。
類方法在堆上分配內(nèi)存,實例方法在堆棧上劲室。
事實上所有的方法都不可能在堆或者堆棧上分配內(nèi)存伦仍,方法作為代碼是被加載到特殊的代碼內(nèi)存區(qū)域,這個內(nèi)存區(qū)域是不可寫的很洋。
實例方法需要先創(chuàng)建實例才可以調(diào)用充蓝,比較麻煩,類方法不用喉磁,比較簡單谓苟。
事實上如果一個方法與他所在類型的實例無關(guān),那么它就應(yīng)該是靜態(tài)的协怒,決不會有人把它寫成實例方法涝焙。所以所有的實例方法都與實例有關(guān),既然與實例有關(guān)孕暇,那么創(chuàng)建實例就是必然的步驟仑撞,沒有麻煩簡單一說。實際上上你可以把所有的實例方法都寫成靜態(tài)的妖滔,將實例作為參數(shù)傳入即可派草。
3.介紹一下分類,能用分類做什么铛楣?內(nèi)部是如何實現(xiàn)的近迁?它為什么會覆蓋掉原來的方法?
類別(Category)主要有3個作用:
將類的實現(xiàn)分散到多個不同文件或多個不同框架中簸州。
創(chuàng)建對私有方法的前向引用鉴竭。
向?qū)ο筇砑臃钦絽f(xié)議。
聲明:@interface 類名(分類名稱) @end
實現(xiàn):@implementation 類名(分類名稱) @end
注意:
(1)在分類只能增加方法,不能增加成員變量,如果要增加成員變量的話該考慮用繼承去實現(xiàn)
(2)在分類實現(xiàn)方法中可以訪問類中的成員變量但是不能訪問類中的屬性@property
(3)在分類中可以重新實現(xiàn)原類中的方法钳枕,但會將原類中的方法覆蓋而失效币叹。
因為在執(zhí)行對象成員方法的時候會優(yōu)先去分類中查找,然后再去原類中去查找璧眠,最后去父類中去查找
(4)如果一個類有多個分類,而且分類中有同名的方法那么最后編譯的分類會將前面編譯的分類覆蓋而執(zhí)行輸出
// 另外一份解釋來自《招聘一個靠譜的 iOS》—參考答案(上)---24
// 類方法:
- 類方法是屬于類對象的
- 類方法只能通過類對象調(diào)用
- 類方法中的self是類對象
- 類方法可以調(diào)用其他的類方法
- 類方法中不能訪問成員變量
- 類方法中不能直接調(diào)用對象方法
// 實例方法:
- 實例方法是屬于實例對象的
- 實例方法只能通過實例對象調(diào)用
- 實例方法中的self是實例對象
- 實例方法中可以訪問成員變量
- 實例方法中直接調(diào)用實例方法
- 實例方法中也可以調(diào)用類方法(通過類名)
4.運行時能增加成員變量么?能增加屬性么责静?如果能袁滥,如何增加?如果不能灾螃,為什么题翻?
Category中不能動態(tài)添加成員變量;
在Objective-C提供的runtime函數(shù)中,確實有一個class_addIvar()函數(shù)用于給類添加成員變量腰鬼,但是閱讀過蘋果的官方文檔的人應(yīng)該會看到:
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之后才可以被使用初家,同樣沒有機會再添加成員變量。
因為方法和屬性并不“屬于”類實例乌助,而成員變量“屬于”類實例溜在。我們所說的“類實例”概念,指的是一塊內(nèi)存區(qū)域他托,包含了isa指針和所有的成員變量掖肋。所以假如允許動態(tài)修改類成員變量布局,已經(jīng)創(chuàng)建出的類實例就不符合類定義了赏参,變成了無效對象志笼。但方法定義是在objc_class中管理的,不管如何增刪類方法把篓,都不影響類實例的內(nèi)存布局纫溃,已經(jīng)創(chuàng)建出的類實例仍然可正常使用。
然而如果在運行時動態(tài)生成一個類韧掩,就可以為其添加成員變量和方法, 如下圖所示:
添加的方法必須是已經(jīng)實現(xiàn)的紊浩,所以先手寫這個方法
如上就動態(tài)創(chuàng)建了一個類。下面我們開始使用這個類疗锐。
5.objc中向一個nil對象發(fā)送消息將會發(fā)生什么坊谁?(返回值是對象,是標(biāo)量滑臊,結(jié)構(gòu)體)
objc中向一個nil對象發(fā)送消息將會發(fā)生什么口芍?