iOS面試題

iOS面試準備

基礎(chǔ)

1. 為什么說Objective-C是一門動態(tài)的語言?

編譯期:即編譯器對語言的編譯階段,編譯時只是對語言進行最基本的檢查報錯,包括詞法分析、語法分析等等闹击,將程序代碼翻譯成計算機能夠識別的語言(例如匯編等),編譯通過并不意味著程序就可以成功運行成艘。

運行時: 即程序通過了編譯這一關(guān)之后編譯好的代碼被裝載到內(nèi)存中跑起來的階段赏半,這個時候會具體對類型進行檢查贺归,而不僅僅是對代碼的簡單掃描分析,此時若出錯程序會崩潰断箫。

OC語言的動態(tài)性主要體現(xiàn)在三個方面:動態(tài)類型(Dynamic typing)拂酣、動態(tài)綁定(Dynamic binding)和動態(tài)加載(Dynamic loading)。

動態(tài)性:即OC的動態(tài)類型仲义、動態(tài)綁定和動態(tài)加載特性婶熬,將對象類型的確定、方法調(diào)用的確定埃撵、代碼和資源的裝載等推遲到運行時進行赵颅,更加靈活;
多態(tài):多態(tài)是面向?qū)ο笞兂烧Z言的特性暂刘,OC作為一門面向?qū)ο蟮恼Z言饺谬,自然具備這種多態(tài)性,多態(tài)性指的是來自不同類的對象可以接受同一消息的能力谣拣,或者說不同對象以自己的方式響應(yīng)相同的消息的能力募寨。


2. 講一下MVC和MVVM,MVP森缠?

這三種都是代碼設(shè)計模式拔鹰。
MVC把代碼分為三層,Model層辅鲸,View層格郁,Controller層。
Model層負責(zé)封裝數(shù)據(jù)独悴、存儲和處理數(shù)據(jù)運算等工作
view層 負責(zé)數(shù)據(jù)展示、監(jiān)聽用戶觸摸等工作
Controller層負責(zé)業(yè)務(wù)邏輯锣尉、事件響應(yīng)刻炒、數(shù)據(jù)加工等工作


3. 為什么代理要用weak?代理的delegate和dataSource有什么區(qū)別自沧?block和代理的區(qū)別?

代理就是一個對象坟奥,在使用代理的時候是:obj.delegate = self;
當(dāng)self持有了obj對象的時候回造成引用循環(huán)。代理用weak可以打破引用循環(huán)拇厢。

delegate和dataSource的區(qū)別在于爱谁,delegate通常在處理交互的事件。dataSource是要獲取數(shù)據(jù)來展示孝偎。


4. 屬性的實質(zhì)是什么访敌?包括哪幾個部分?屬性默認的關(guān)鍵字都有哪些衣盾?@dynamic關(guān)鍵字和@synthesize關(guān)鍵字是用來做什么的寺旺?

屬性的實質(zhì)是實例對象中數(shù)據(jù)存儲的地址爷抓。
包含三部分:(對象的實例變量,包括類型和名字) 獲取屬性方法 設(shè)置屬性方法
@property = ivar + getter + setter;

@property (nonatomic, copy) NSString *name;

//T@"NSString",C,N,V_name
//T 類型
//C copy
//N nonatomic
//V 實例變量

@synthesize的語義是如果你沒有手動實現(xiàn)setter方法和getter方法阻塑,那么編譯器會自動為你加上這兩個方法蓝撇。

@dynamic告訴編譯器,屬性的setter與getter方法由用戶自己實現(xiàn),不自動生成陈莽。(當(dāng)然對于readonly的屬性只需提供getter即可)渤昌。假如一個屬性被聲明為@dynamic var,然后你沒有提供@setter方法和@getter方法走搁,編譯的時候沒問題独柑,但是當(dāng)程序運行到instance.var =someVar,由于缺setter方法會導(dǎo)致程序崩潰朱盐;


5. 屬性的默認關(guān)鍵字是什么群嗤?

對應(yīng)基本數(shù)據(jù)類型默認關(guān)鍵字是
atomic,readwrite,assign
對于普通的OC對象
atomic,readwrite,strong


6. NSString為什么要用copy關(guān)鍵字,如果用strong會有什么問題兵琳?(注意:這里沒有說用strong就一定不行狂秘。使用copy和strong是看情況而定的)

NSString *str1 = @"abc"; //如果strongStr是Strong修飾的話 self.strongStr = str1; self.copyStr = str1; str1 = @"zxc"; //self.strongStr -> @"zxc",strongStr的指針是指向str1的內(nèi)存地址躯肌,修改str1的時候者春,strongStr也會跟著改變,可能造成意外的結(jié)果清女。 //而copy修飾的屬性會自動生成新的地址钱烟,self.copyStr->@"abc",copyStr把str的值復(fù)制到新的地址上。


7. 如何令自己所寫的對象具有拷貝功能?

遵守NSCopying協(xié)議
實現(xiàn)- (id)copyWithZone:(nullable NSZone *)zone;協(xié)議方法

@implementation Person
- (id)copyWithZone:(NSZone *)zone
{
  Person *p = [[[self class] alloc] init]; // <== 注意這里
  p.userId = self.userId;
  return p;
}
@end

@implementation Student
- (id)copyWithZone:(NSZone *)zone
{
  Student *s = [super copyWithZone:zone];
  s.studentId = self.studentId;
  return s;
}
@end



8. 可變集合類 和 不可變集合類的 copy 和 mutablecopy有什么區(qū)別嫡丙?如果是集合是內(nèi)容復(fù)制的話拴袭,集合里面的元素也是內(nèi)容復(fù)制么?

使用copy未必是深拷貝曙博,但使用mutablecopy一定是深拷貝拥刻。

淺拷貝:指針(地址)拷貝,不會產(chǎn)生新對象父泳;深拷貝:內(nèi)容拷貝般哼,會產(chǎn)生新對象

當(dāng)不可變字符串(或不可變數(shù)組,不可變集合惠窄,不可變字典)調(diào)用copy的時候蒸眠,指針地址沒有發(fā)生改變,也就意味著沒有產(chǎn)生新的對象杆融,所以屬于淺拷貝楞卡;

當(dāng)可變字符串(或可變數(shù)組,可變集合,可變字典)調(diào)用copy的時候臀晃,指針地址發(fā)生了改變觉渴,也就意味著產(chǎn)生新的對象,所以屬于深拷貝徽惋;

當(dāng)可變字符串(或可變數(shù)組案淋,可變集合,可變字典調(diào)用mutableCopy的時候险绘,指針地址發(fā)生了改變踢京,意味著產(chǎn)生新的對象,所以屬于深拷貝宦棺。

當(dāng)不可變字符串(或不可變數(shù)組瓣距,不可變集合,不可變字典)調(diào)用mutableCopy的時候代咸,指針地址發(fā)生了改變蹈丸,意味著產(chǎn)生新的對象,所以屬于深拷貝呐芥。

集合對象的內(nèi)容復(fù)制僅限于對象本身逻杖,對象元素仍然是指針復(fù)制。

// 屬性為copy的時候思瘟,等價于下面的代碼
- (void)setName:(NSString *)name {
      if (_name != name) {
         [_name release];
          _name = [name copy];
       }
}

9. 為什么IBOutlet修飾的UIView也適用weak關(guān)鍵字荸百?

使用storyboard(xib不行)創(chuàng)建的vc,會有一個叫_topLevelObjectsToKeepAliveFromStoryboard的私有數(shù)組強引用所有top level的對象滨攻,所以這時即便outlet聲明成weak也沒關(guān)系


10. nonatomic和atomic的區(qū)別够话?atomic是絕對的線程安全么?為什么光绕?如果不是女嘲,那應(yīng)該如何實現(xiàn)?

atomic:默認是有該屬性的诞帐,這個屬性是為了保證程序在多線程情況下澡为,編譯器會自動生成一些互斥加鎖代碼,避免該變量的讀寫不同步問題景埃。
nonatomic:如果該對象無需考慮多線程的情況,請加入這個屬性顶别,這樣會讓編譯器少生成一些互斥加鎖代碼谷徙,可以提高效率。
在iOS中使用同步鎖的開銷比較大驯绎, 這會帶來性能問題完慧。

如果不加鎖的話(或者說使用nonatomic語義),那么當(dāng)其中一個線程正在改寫某屬性值的時候剩失,另外一個線程也許會突然闖入屈尼,把尚未修改好的屬性值讀取出來册着。發(fā)證這種情況時,線程讀取到屬性值可能不對脾歧。

一般iOS程序中甲捏,所有屬性都聲明為nonatomic。這樣做的原因是:
在iOS中使用同步鎖的開銷比較大鞭执, 這會帶來性能問題司顿。一般情況下并不要求屬性必須是“原子的”,因為這并不能保證“線程安全”(thread safety)兄纺,若要實現(xiàn)“線程安全”的操作大溜,還需采用更為深層的鎖定機制才醒。

nonatomic的內(nèi)存管理語義是非原子性的估脆,非原子性的操作本來就是線程不安全钦奋,而atomic的操作是原子性的,但并不意味著他就是線程安全的疙赠,它會增加正確的幾率付材,能夠更好的避免線程錯誤,但仍舊是不安全的棺聊。

幾種線程鎖:
OSSpinLock: 46.15 ms
dispatch_semaphore: 56.50 ms
pthread_mutex: 178.28 ms
NSCondition: 193.38 ms
NSLock: 175.02 ms
pthread_mutex(recursive): 172.56 ms
NSRecursiveLock: 157.44 ms
NSConditionLock: 490.04 ms
@synchronized: 371.17 ms

總的來說:

OSSpinLock和dispatch_semaphore的效率遠遠高于其他伞租。

@synchronized和NSConditionLock效率較差。

鑒于OSSpinLock的不安全限佩,所以我們在開發(fā)中如果考慮性能的話葵诈,建議使用dispatch_semaphore。

如果不考慮性能祟同,只是圖個方便的話作喘,那就使用@synchronized。


11. UICollectionView自定義layout如何實現(xiàn)晕城?


12. 用StoryBoard開發(fā)界面有什么弊端泞坦?如何避免?

目中用到StoryBoard的地方較多談下想法,首先團隊開發(fā)中用StoryBoard,如果模塊劃分的不是那么獨立,會有多人共同寫一個模塊的情況,那最后不要用StoryBoard,應(yīng)為SVN經(jīng)常會沖突導(dǎo)致更新下的代碼會有問題,可能需要恢復(fù)到上導(dǎo)致沖突前一版本才能解決砖顷。


13. 進程和線程的區(qū)別贰锁?同步異步的區(qū)別?

進程本身不會運行滤蝠,是線程的容器豌熄。程序本身只是指令的集合,進程才是程序(那些指令)的真正運行物咳。若干進程有可能與同一個程序相關(guān)系锣险,且每個進程皆可以同步(循序)或不同步(平行)的方式獨立運行。進程為現(xiàn)今分時系統(tǒng)的基本運作單位

進程:每個進程之間是獨立的,每個進程均運行在其專用且受保護的內(nèi)存空間內(nèi)

線程:操作系統(tǒng)能夠進行運算調(diào)度的最小單位芯肤。它被包涵在進程之中巷折,一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發(fā)多個線程崖咨,每條線程并行執(zhí)行不同的任務(wù)锻拘。

1個進程要想執(zhí)行任務(wù),必須得有線程(每1個進程至少要有1條線程)

14991779754660.jpg

14. 線程間通信掩幢?

線程間通信的體現(xiàn):
(1 ).一個線程傳遞數(shù)據(jù)給另一個線程
(2).在一個線程中執(zhí)行完特定任務(wù)后逊拍,轉(zhuǎn)到另一個線程繼續(xù)執(zhí)行任務(wù)

在子線程計算然后 在主線程刷新也是一種線程傳遞數(shù)據(jù)

15. GCD的一些常用的函數(shù)?(group际邻,barrier芯丧,信號量,線程同步)

關(guān)于GCD鏈接

16. 如何使用隊列來避免資源搶奪世曾?

當(dāng)我們使用多線程來訪問同一個數(shù)據(jù)的時候缨恒,就有可能造成數(shù)據(jù)的不準確性。這個時候我么可以使用線程鎖的來來綁定轮听。也是可以使用串行隊列來完成骗露。如:fmdb就是使用FMDatabaseQueue,來解決多線程搶奪資源血巍。


17. 數(shù)據(jù)持久化的幾個方案

plist文件
NSUserDefaults
NSKeyedArchiver
SQLite 3 (FMDB封裝了SQLite3)
CoreData


18. 說一下AppDelegate的幾個方法萧锉?從后臺到前臺調(diào)用了哪些方法?第一次啟動調(diào)用了哪些方法述寡?從前臺到后臺調(diào)用了哪些方法柿隙?

– (void)applicationDidFinishLaunching:(UIApplication *)application; 此方法基本已經(jīng)棄用,改用第2個方法代替鲫凶。

– (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions: 當(dāng)應(yīng)用程序啟動時(不包括已在后臺的情況下轉(zhuǎn)到前臺)禀崖,調(diào)用此回調(diào)。launchOptions是啟動參數(shù)螟炫,假如用戶通過點擊push通知啟動的應(yīng)用波附,這個參數(shù)里會存儲一些push通知的信息。

– (void)applicationDidBecomeActive:(UIApplication *)application; 當(dāng)應(yīng)用程序全新啟動昼钻,或者在后臺轉(zhuǎn)到前臺掸屡,完全激活時,都會調(diào)用這個方法然评。如果應(yīng)用程序是以前運行在后臺折晦,這時可以選擇刷新用戶界面。

– (void)applicationWillResignActive:(UIApplication *)application; 當(dāng)應(yīng)用從活動狀態(tài)主動到非活動狀態(tài)的應(yīng)用程序時會調(diào)用這個方法沾瓦。這可導(dǎo)致產(chǎn)生某些類型的臨時中斷(如傳入電話呼叫或SMS消息)。或者當(dāng)用戶退出應(yīng)用程 序贯莺,它開始過渡到的背景狀態(tài)风喇。使用此方法可以暫停正在進行的任務(wù),禁用定時器缕探,降低OpenGL ES的幀速率魂莫。游戲應(yīng)該使用這種方法來暫停游戲。 調(diào)用時機可能有以下幾種:鎖屏爹耗,按HOME鍵耙考,下接狀態(tài)欄,雙擊HOME鍵彈出低欄潭兽,等情況倦始。

– (BOOL)application:(UIApplication )application handleOpenURL:(NSURL )url; 這個方法已不再支持,可能會在以后某個版本中去掉山卦。建議用下面方法代替

– (BOOL)application:(UIApplication )application openURL:(NSURL )url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation NS_AVAILABLE_IOS(4_2); 當(dāng)用戶通過其它應(yīng)用啟動本應(yīng)用時鞋邑,會回調(diào)這個方法,url參數(shù)是其它應(yīng)用調(diào)用openURL:方法時傳過來的账蓉。

– (void)applicationDidReceiveMemoryWarning:(UIApplication *)application; 當(dāng)應(yīng)用可用內(nèi)存不足時枚碗,會調(diào)用此方法,在這個方法中铸本,應(yīng)該盡量去清理可能釋放的內(nèi)存肮雨。如果實在不行,可能會被強行退出應(yīng)用箱玷。

– (void)applicationWillTerminate:(UIApplication *)application; 當(dāng)應(yīng)用退出怨规,并且進程即將結(jié)束時會調(diào)到這個方法,一般很少主動調(diào)到汪茧,更多是內(nèi)存不足時是被迫調(diào)到的椅亚,我們應(yīng)該在這個方法里做一些數(shù)據(jù)存儲操作。

-(void)application:(UIApplication )application didRegisterForRemoteNotificationsWithDeviceToken: -(void)application:(UIApplication )application didFailToRegisterForRemoteNotificationsWithError:(NSError )error NS_AVAILABLE_IOS(3_0); 當(dāng)客戶端注冊遠程通知時舱污,會回調(diào)上面兩個方法呀舔。 如果成功,則回調(diào)第一個扩灯,客戶端把deviceToken取出來發(fā)給服務(wù)端媚赖,push消息的時候要用。 如果失敗了珠插,則回調(diào)第二個惧磺,可以從error參數(shù)中看一下失敗原因。 注:注冊遠程通知使用如下方法: UIRemoteNotificationType t = UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound; [[UIApplication sharedApplication] registerForRemoteNotificationTypes:t];

– (void)application:(UIApplication )application didReceiveRemoteNotification: 當(dāng)應(yīng)用在前臺運行中捻撑,收到遠程通知時磨隘,會回調(diào)這個方法缤底。 當(dāng)應(yīng)用在后臺狀態(tài)時,點擊push消息啟動應(yīng)用番捂,也會回調(diào)這個方法个唧。

– (void)application:(UIApplication )application didReceiveLocalNotification:(UILocalNotification )notification NS_AVAILABLE_IOS(4_0); 當(dāng)應(yīng)用收到本地通知時會調(diào)這個方法,同上面一個方法類似设预。 如果在前臺運行狀態(tài)直接調(diào)用徙歼,如果在后臺狀態(tài),點擊通知啟動時鳖枕,也會回調(diào)這個方法

– (void)applicationDidEnterBackground:(UIApplication *)application NS_AVAILABLE_IOS(4_0); 當(dāng)用戶從臺前狀態(tài)轉(zhuǎn)入后臺時魄梯,調(diào)用此方法。使用此方法來釋放資源共享宾符,保存用戶數(shù)據(jù)酿秸,無效計時器,并儲存足夠的應(yīng)用程序狀態(tài)信息的情況下被終止后吸奴,將應(yīng)用 程序恢復(fù)到目前的狀態(tài)允扇。如果您的應(yīng)用程序支持后臺運行,這種方法被調(diào)用则奥,否則調(diào)用applicationWillTerminate:用戶退出考润。

– (void)applicationWillEnterForeground; 當(dāng)應(yīng)用在后臺狀態(tài),將要進行動前臺運行狀態(tài)時读处,會調(diào)用此方法糊治。如果應(yīng)用不在后臺狀態(tài),而是直接啟動罚舱,則不會回調(diào)此方法井辜。


19. NSCache優(yōu)于NSDictionary的幾點?

NSDictionary *dic = @{
                     @(1) : @(1),
                     @(2) : @(2)
};
NSLog(@"%@",dic.allKeys);

注意一點它和NSDictionary區(qū)別就是管闷,NSCache 中的key不必實現(xiàn)copy粥脚,NSDictionary中的key必須實現(xiàn)copy

NSCache優(yōu)于NSDictionary的幾點:

  1. 當(dāng)系統(tǒng)資源將要耗盡時,NSCache具備自動刪減緩沖的功能包个。并且還會先刪減“最久未使用”的對象刷允。
  1. NSCache不拷貝鍵,而是保留鍵碧囊。因為并不是所有的鍵都遵從拷貝協(xié)議(字典的鍵是必須要支持拷貝協(xié)議的树灶,有局限性)。
  2. NSCache是線程安全的:不編寫加鎖代碼的前提下糯而,多個線程可以同時訪問NSCache天通。

20. 知不知道Designated Initializer?使用它的時候有什么需要注意的問題熄驼?

Designated Initializer 指定初始化器

  1. 每個類的正確初始化過程應(yīng)當(dāng)是按照從子類到父類的順序像寒,依次調(diào)用每個類的Designated Initializer烘豹。并且用父類的Designated Initializer初始化一個子類對象,也需要遵從這個過程萝映。
  1. 如果子類指定了新的初始化器吴叶,那么在這個初始化器內(nèi)部必須調(diào)用父類的Designated Initializer。并且需要重寫父類的Designated Initializer序臂,將其指向子類新的初始化器
- (instancetype)initWithFrame:(CGRect)frame andName:(NSString *)name{ 
  //incorrect 
    if (self = [super init]){ 
        self.name=name; 
    } 
    return self; 
}

21. 實現(xiàn)description方法能取到什么效果?

重寫該方法实束。
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level

在使用NSObject類替換%@占位符時奥秆,會調(diào)用description相關(guān)方法,所以只要實現(xiàn)此方法咸灿,就可以起到修改打印內(nèi)容的作用构订。因此對于系統(tǒng)的類,可用增加分類的方式實現(xiàn)避矢,而自己的類悼瘾,就是增加方法。


22. objc使用什么機制管理對象內(nèi)存审胸?

1).MRC(manual retain-release)手動內(nèi)存管理
2).ARC(automatic reference counting)自動引用計數(shù)


Block

block的實質(zhì)是什么亥宿?一共有幾種block?都是什么情況下生成的砂沛?

block也是OC的對象
_NSConcreteStackBlock 保存在棧中的block仁烹,出棧時會被銷毀
_NSConcreteGlobalBlock 全局的靜態(tài)block酵使,不會訪問任何外部變量
_NSConcreteMallocBlock 保存在堆中的block,當(dāng)引用計數(shù)為0時會被銷毀

關(guān)于block知識


為什么在默認情況下無法修改被block捕獲的變量? __block都做了什么扶歪?

配置在全局的GlobalBlock可以出了作用域還是能繼續(xù)訪問,但是在棧上的StackBlock就廢棄了勿她,因此為了出了作用域能繼續(xù)使用适荣,OC提供了把Block和__block這兩個東西從棧上復(fù)制到堆上的方法來解決這個問題。而_forwarding其實既可以指向自己苹享,也可以指向復(fù)制后的自己双絮,也就是說有了這個指針的存在,無論__block變量配置在堆上還是棧上都能夠正確的訪問__block變量富稻。


模擬一下循環(huán)引用的一個情況掷邦?block實現(xiàn)界面反向傳值如何實現(xiàn)?

self.blockClass = [[LMBlockClass alloc] init];

[self.blockClass testBlock1:^{
  self.string = @"ssss";
}];

但如果你使用一些參數(shù)中可能含有 ivar 的系統(tǒng) api 椭赋,如 GCD 抚岗、NSNotificationCenter就要小心一點:比如GCD 內(nèi)部如果引用了 self,而且 GCD 的其他參數(shù)是 ivar哪怔,則要考慮到循環(huán)引用:

__weak __typeof__(self) weakSelf = self;
dispatch_group_async(_operationsGroup, _operationsQueue, ^
{
    __typeof__(self) strongSelf = weakSelf;
    [strongSelf doSomething];
    [strongSelf doSomethingElse];
} );

 __weak __typeof__(self) weakSelf = self;
 _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey" object:nil queue:nil usingBlock:^(NSNotification *note) {
     __typeof__(self) strongSelf = weakSelf;
     [strongSelf dismissModalViewControllerAnimated:YES];
 }];


Runtime

objc在向一個對象發(fā)送消息時宣蔚,發(fā)生了什么向抢?

1.消息由接收者,選擇子及參數(shù)構(gòu)成胚委。給某對象“發(fā)送消息”(invoke a method)也就相當(dāng)于在該對象上調(diào)用方法挟鸠。

//1.self是接收者 2.messageName:是選擇子 3.選擇子和參數(shù)合起來稱為“消息”
id returnValue = [self messageName:@"messageValue"];

2.發(fā)給某對象的全部消息都要由“動態(tài)消息派發(fā)系統(tǒng)”來處理,該系統(tǒng)會查出對應(yīng)的方法亩冬,并執(zhí)行其代碼艘希。
編譯器看到消息后,會將上面轉(zhuǎn)換為一條標準的C語言函數(shù)調(diào)用硅急。
第一個參數(shù)是接收者 第二個參數(shù)是選擇子 后面的參數(shù)就是消息中的參數(shù)
void objc_msgSend(id self,SEL cmd,....);
id objc_returnValue = objc_msgSend(self,@selector(messageName:),@"messageValue");

執(zhí)行過程 objc_msgSend 會根據(jù)接收者和選擇子的類型來調(diào)用適當(dāng)?shù)姆椒?br> * 1.在接收者所在的類中搜其“方法列表”覆享,找到相符的方法,就跳至其實現(xiàn)代碼营袜。
* 2.找不到就沿著繼承體系繼續(xù)往上找撒顿,等找到合適的方法后再跳轉(zhuǎn);
* 3.如果最終還是找不到相符的荚板,就執(zhí)行“消息轉(zhuǎn)發(fā)”操作


什么時候會報unrecognized selector錯誤凤壁?iOS有哪些機制來避免走到這一步?

當(dāng)對象無法響應(yīng)該方法和消息轉(zhuǎn)發(fā)沒有處理該方法時就報該錯誤跪另。


能否向編譯后得到的類中增加實例變量拧抖?能否向運行時創(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 指向的對象內(nèi)存地址是a业栅,那么就會以a為鍵秒咐, 在這個 weak 表中搜索谬晕,找到所有以a為鍵的 weak 對象,從而設(shè)置為 nil携取。

我們可以設(shè)計一個函數(shù)(偽代碼)來表示上述機制:

objc_storeWeak(&a, b)函數(shù):

objc_storeWeak函數(shù)把第二個參數(shù)--賦值對象(b)的內(nèi)存地址作為鍵值key攒钳,將第一個參數(shù)--weak修飾的屬性變量(a)的內(nèi)存地址(&a)作為value,注冊到 weak 表中雷滋。如果第二個參數(shù)(b)為0(nil)不撑,那么把變量(a)的內(nèi)存地址(&a)從weak表中刪除,

你可以把objc_storeWeak(&a, b)理解為:objc_storeWeak(value, key)晤斩,并且當(dāng)key變nil燎孟,將value置nil。

在b非nil時尸昧,a和b指向同一個內(nèi)存地址,在b變nil時旷偿,a變nil烹俗。此時向a發(fā)送消息不會崩潰:在Objective-C中向nil發(fā)送消息是安全的。

而如果a是由assign修飾的萍程,則: 在b非nil時幢妄,a和b指向同一個內(nèi)存地址,在b變nil時茫负,a還是指向該內(nèi)存地址蕉鸳,變野指針。此時向a發(fā)送消息極易崩潰忍法。


RunLoop

runloop是來做什么的潮尝?runloop和線程有什么關(guān)系?主線程默認開啟了runloop么饿序?子線程呢勉失?

RunLoop 的概念

一般來講,一個線程一次只能執(zhí)行一個任務(wù)原探,執(zhí)行完成后線程就會退出乱凿。如果我們需要一個機制,讓線程能隨時處理事件但并不退出咽弦,通常的代碼邏輯是這樣的:

function loop() {
    initialize();
    do {
        var message = get_next_message();
        process_message(message);
    } while (message != quit);
}

RunLoop 實際上就是一個對象徒蟆,iOS系統(tǒng)提供了兩個這樣的對象:NSRunLoop 和 CFRunLoopRef。這個對象管理了其需要處理的事件和消息型型,并提供了一個入口函數(shù)來執(zhí)行上面 Event Loop 的邏輯段审。線程執(zhí)行了這個函數(shù)后,就會一直處于這個函數(shù)內(nèi)部 "接受消息->等待->處理" 的循環(huán)中输莺,直到這個循環(huán)結(jié)束(比如傳入 quit 的消息)戚哎,函數(shù)返回裸诽。

RunLoop這個對象在循環(huán)中用來處理程序運行過程中出現(xiàn)的各種事件(比如說觸摸事件、UI刷新事件型凳、定時器事件丈冬、Selector事件),從而保持程序的持續(xù)運行甘畅;而且在沒有事件處理的時候埂蕊,會進入睡眠模式,從而節(jié)省CPU資源疏唾,提高程序性能蓄氧。

CFRunLoopRef 是在 CoreFoundation 框架內(nèi)的,它提供了純 C 函數(shù)的 API槐脏,所有這些 API 都是線程安全的喉童。

NSRunLoop 是基于 CFRunLoopRef 的封裝,提供了面向?qū)ο蟮?API顿天,但是這些 API 不是線程安全的堂氯。

runloop和線程有什么關(guān)系

  1. 一條線程對應(yīng)一個RunLoop對象,每條線程都有唯一一個與之對應(yīng)的RunLoop對象牌废。
  1. 我們只能在當(dāng)前線程中操作當(dāng)前線程的RunLoop咽白,而不能去操作其他線程的RunLoop。
  2. RunLoop對象在第一次獲取RunLoop時創(chuàng)建鸟缕,銷毀則是在線程結(jié)束的時候晶框。
  3. 主線程的RunLoop對象系統(tǒng)自動幫助我們創(chuàng)建好了(原理如下),而子線程的RunLoop對象需要我們主動創(chuàng)建懂从。

主線程默認開啟了runloop授段,子線程的runloop默認關(guān)閉,第一次獲取的時候才創(chuàng)建莫绣,有時候用不到浪費資源畴蒲。runloop有資源才不會銷毀,沒資源會自定銷毀对室。

1877784-6ab632fc118e31f3.jpg

runloop的mode是用來做什么的模燥?有幾種mode?

一個 RunLoop 包含若干個 Mode掩宜,每個 Mode 又包含若干個 Source/Timer/Observer蔫骂。每次調(diào)用 RunLoop 的主函數(shù)時,只能指定其中一個 Mode牺汤,這個Mode被稱作 CurrentMode辽旋。如果需要切換 Mode,只能退出 Loop,再重新指定一個 Mode 進入补胚。這樣做主要是為了分隔開不同組的 Source/Timer/Observer码耐,讓其互不影響。

CFRunLoopModeRef

系統(tǒng)默認定義了多種運行模式(CFRunLoopModeRef)溶其,如下:

  1. kCFRunLoopDefaultMode:App的默認運行模式骚腥,通常主線程是在這個運行模式下運行
  1. UITrackingRunLoopMode:跟蹤用戶交互事件(用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他Mode影響)
  2. UIInitializationRunLoopMode:在剛啟動App時第進入的第一個 Mode瓶逃,啟動完成后就不再使用
  3. GSEventReceiveRunLoopMode:接受系統(tǒng)內(nèi)部事件束铭,通常用不到
  4. kCFRunLoopCommonModes:偽模式,不是一種真正的運行模式(后邊會用到)

其中kCFRunLoopDefaultMode厢绝、UITrackingRunLoopMode契沫、kCFRunLoopCommonModes是我們開發(fā)中需要用到的模式

而當(dāng)我們拖動ScllorView的時候,RunLoop就結(jié)束NSDefaultRunLoopMode昔汉,切換到了UITrackingRunLoopMode模式下懈万,這個模式下沒有添加NSTimer,所以我們的NSTimer就不工作了靶病。

[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];钞速,也就是將定時器添加到當(dāng)前RunLoop的UITrackingRunLoopMode下,你就會發(fā)現(xiàn)定時器只會在拖動Text View的模式下工作嫡秕,而不做操作的時候定時器就不工作

我們之前說過的偽模式(kCFRunLoopCommonModes),這其實不是一種真實的模式苹威,而是一種標記模式昆咽,意思就是可以在打上Common Modes標記的模式下運行。

1877784-2177aa2828b1ad34.png

CFRunLoopTimerRef是定時源(RunLoop模型圖中提到過)牙甫,理解為基于時間的觸發(fā)器掷酗,基本上就是NSTimer

CFRunLoopSourceRef是事件源(RunLoop模型圖中提到過),CFRunLoopSourceRef有兩種分類方法窟哺。
同時我們可以看到11行中有Sources0泻轰,也就是說我們點擊事件是屬于Sources0函數(shù)的,點擊事件就是在Sources0中處理的且轨。

而至于Sources1浮声,則是用來接收、分發(fā)系統(tǒng)事件旋奢,然后再分發(fā)到Sources0中處理的泳挥。

CFRunLoopObserverRef是觀察者,用來監(jiān)聽RunLoop的狀態(tài)改變

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),               // 即將進入Loop:1
    kCFRunLoopBeforeTimers = (1UL << 1),        // 即將處理Timer:2    
    kCFRunLoopBeforeSources = (1UL << 2),       // 即將處理Source:4
    kCFRunLoopBeforeWaiting = (1UL << 5),       // 即將進入休眠:32
    kCFRunLoopAfterWaiting = (1UL << 6),        // 即將從休眠中喚醒:64
    kCFRunLoopExit = (1UL << 7),                // 即將從Loop中退出:128
    kCFRunLoopAllActivities = 0x0FFFFFFFU       // 監(jiān)聽全部狀態(tài)改變  
};


蘋果是如何實現(xiàn)Autorelease Pool的至朗?

autoreleasepool 以一個隊列數(shù)組的形式實現(xiàn),主要通過下列三個函數(shù)完成.

objc_autoreleasepoolPush
objc_autoreleasepoolPop
objc_autorelease
看函數(shù)名就可以知道屉符,對 autorelease 分別執(zhí)行 push,和 pop 操作。銷毀對象時執(zhí)行release操作矗钟。

舉例說明:我們都知道用類方法創(chuàng)建的對象都是 Autorelease 的唆香,那么一旦 Person 出了作用域,當(dāng)在 Person 的 dealloc 方法中打上斷點吨艇,我們就可以看到這樣的調(diào)用堆棧信息:

類結(jié)構(gòu)

isa指針躬它?(對象的isa,類對象的isa秸应,元類的isa都要說)

類方法和實例方法有什么區(qū)別虑凛?

類方法:
類方法是屬于類對象的
類方法只能通過類對象調(diào)用
類方法中的self是類對象
類方法可以調(diào)用其他的類方法
類方法中不能訪問成員變量
類方法中不能直接調(diào)用對象方法

實例方法:
實例方法是屬于實例對象的
實例方法只能通過實例對象調(diào)用
實例方法中的self是實例對象
實例方法中可以訪問成員變量
實例方法中直接調(diào)用實例方法
實例方法中也可以調(diào)用類方法(通過類名)


介紹一下分類,能用分類做什么软啼?內(nèi)部是如何實現(xiàn)的桑谍?它為什么會覆蓋掉原來的方法?

運行時能增加成員變量么祸挪?能增加屬性么锣披?如果能,如何增加贿条?如果不能雹仿,為什么?

objc中向一個nil對象發(fā)送消息將會發(fā)生什么整以?(返回值是對象胧辽,是標量,結(jié)構(gòu)體)

如果 spouse 對象為 nil公黑,那么發(fā)送給 nil 的消息 mother 也將返回 nil邑商。 2. 如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*)凡蚜,float人断,double,long double 或者 long long 的整型標量朝蜘,發(fā)送給 nil 的消息將返回0恶迈。 2. 如果方法返回值為結(jié)構(gòu)體,發(fā)送給 nil 的消息將返回0。結(jié)構(gòu)體中各個字段的值將都是0谱醇。 2. 如果方法的返回值不是上述提到的幾種情況暇仲,那么發(fā)送給 nil 的消息的返回值將是未定義的。


高級

UITableview的優(yōu)化方法(緩存高度副渴,異步繪制熔吗,減少層級,hide佳晶,避免離屏渲染)

有沒有用過運行時桅狠,用它都能做什么?(交換方法,創(chuàng)建類中跌,給新創(chuàng)建的類增加方法咨堤,改變isa指針)

看過哪些第三方框架的源碼?都是如何實現(xiàn)的漩符?(如果沒有一喘,問一下多圖下載的設(shè)計)

SDWebImage的緩存策略?

AFN為什么添加一條常駐線程嗜暴?

KVO的使用凸克?實現(xiàn)原理?(為什么要創(chuàng)建子類來實現(xiàn))

當(dāng)你觀察一個對象時闷沥,一個新的類會被動態(tài)創(chuàng)建萎战。這個類繼承自該對象的原本的類,并重寫了被觀察屬性的 setter 方法舆逃。重寫的 setter 方法會負責(zé)在調(diào)用原 setter 方法之前和之后蚂维,通知所有觀察對象:值的更改。最后通過 isa 混寫(isa-swizzling) 把這個對象的 isa 指針 ( isa 指針告訴 Runtime 系統(tǒng)這個對象的類是什么 ) 指向這個新創(chuàng)建的子類路狮,對象就神奇的變成了新創(chuàng)建的子類的實例虫啥。我畫了一張示意圖,


687474703a2f2f6936322e74696e797069632e636f6d2f7379353775722e6a7067.png

KVC的使用奄妨?實現(xiàn)原理涂籽?(KVC拿到key以后,是如何賦值的砸抛?知不知道集合操作符又活,能不能訪問私有屬性,能不能直接訪問_ivar)

KVC 支持實例變量锰悼,KVO 只能手動支持手動設(shè)定實例變量的KVO實現(xiàn)監(jiān)聽

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市团赏,隨后出現(xiàn)的幾起案子箕般,更是在濱河造成了極大的恐慌,老刑警劉巖舔清,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丝里,死亡現(xiàn)場離奇詭異,居然都是意外死亡体谒,警方通過查閱死者的電腦和手機杯聚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抒痒,“玉大人幌绍,你說我怎么就攤上這事。” “怎么了傀广?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵颁独,是天一觀的道長。 經(jīng)常有香客問我伪冰,道長誓酒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任贮聂,我火速辦了婚禮靠柑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吓懈。我一直安慰自己歼冰,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布骄瓣。 她就那樣靜靜地躺著停巷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪榕栏。 梳的紋絲不亂的頭發(fā)上畔勤,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音扒磁,去河邊找鬼庆揪。 笑死,一個胖子當(dāng)著我的面吹牛妨托,可吹牛的內(nèi)容都是我干的缸榛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼兰伤,長吁一口氣:“原來是場噩夢啊……” “哼内颗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起敦腔,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤均澳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后符衔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體找前,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年判族,在試婚紗的時候發(fā)現(xiàn)自己被綠了躺盛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡形帮,死狀恐怖槽惫,靈堂內(nèi)的尸體忽然破棺而出周叮,到底是詐尸還是另有隱情,我是刑警寧澤躯枢,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布则吟,位于F島的核電站,受9級特大地震影響锄蹂,放射性物質(zhì)發(fā)生泄漏氓仲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一得糜、第九天 我趴在偏房一處隱蔽的房頂上張望敬扛。 院中可真熱鬧,春花似錦朝抖、人聲如沸啥箭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽急侥。三九已至,卻和暖如春侮邀,著一層夾襖步出監(jiān)牢的瞬間坏怪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工绊茧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留铝宵,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓华畏,卻偏偏與公主長得像鹏秋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子亡笑,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,125評論 29 470
  • 1侣夷,NSObject中description屬性的意義,它可以重寫嗎?答案:每當(dāng) NSLog(@"")函數(shù)中出現(xiàn) ...
    eightzg閱讀 4,132評論 2 19
  • 基礎(chǔ) 1. 為什么說Objective-C是一門動態(tài)的語言仑乌? 2. 講一下MVC和MVVM百拓,MVP? 3. 為...
    波妞和醬豆子閱讀 3,307評論 0 46
  • 把網(wǎng)上的一些結(jié)合自己面試時遇到的面試題總結(jié)了一下绝骚,以后有新的還會再加進來。 1. OC 的理解與特性 OC 作為一...
    AlaricMurray閱讀 2,546評論 0 20
  • 基礎(chǔ) 1.為什么說Objective-C是一門動態(tài)的語言祠够? 所謂的動態(tài)類型語言压汪,意思就是類型的檢查是在運行時做的。...
    陽明先生_x閱讀 1,003評論 0 17