iOS面試寶典《二》--經典案例


經典案例

===CGD考察===
下面代碼的輸出順序

- (void)gcdTest {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"4");
    });
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"5");
    });
    [self performSelector:@selector(test2)];
    [self performSelector:@selector(test3) withObject:nil afterDelay:0];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"6");
    });
    [self test1];
}

- (void)test1 {
    NSLog(@"1");
}
- (void)test2 {
    NSLog(@"2");
}
- (void)test3 {
    NSLog(@"3");
}

  /*
     蘋果文檔
     Enqueue a block for execution at the specified time.
     This function waits until the specified time and then asynchronously adds block to the specified queue.
    
     dispatch_after 第二個參數為0别智,以此可以理解為在當前時刻往主隊列添加一個block, 文檔中 asynchronously 可以看出是在當前時刻
     添加到主隊列的尾部
     */
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"4");
    });
   
    /*
    這里主要考的是 dispatch_async 這個函數的特點照藻,往指定的隊列添加一個block立馬返回
       
    以下代碼在主線程上執(zhí)行
     dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"A");
     });
     NSLog(@"B");
      結果為 BA
    
     */
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"5");
    });
   
    /*
     performSelector:
     先看蘋果文檔的解析:
     Sends a specified message to the receiver and returns the result of the message.
    
     那么這句話相當于
     [self test2]
     */
    [self performSelector:@selector(test2)];
   
    /*
     performSelector:withObject:afterDelay:
     Invokes a method of the receiver on the current thread using the default mode after a delay.
     This method sets up a timer to perform the aSelector message on the current thread’s run loop. The timer is configured to run in the default mode (NSDefaultRunLoopMode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in the default mode; otherwise, the timer waits until the run loop is in the default mode.
    
     這些解析中最關鍵的一個單詞是 NSDefaultRunLoopMode
     NSDefaultRunLoopMode 是當前線程上正在執(zhí)行的任務優(yōu)先,
     那么如果當前線程上有其他任務要執(zhí)行魔策,test3 先讓步氓皱,然后在輪到它執(zhí)行
    
     如果往當前隊列中 dispatch_async 一下,通過測試续室,他的優(yōu)先級跟 performSelector:withObject:afterDelay: 是同等的栋烤,
     換句話說就是誰先誰先執(zhí)行
     */
    [self performSelector:@selector(test3) withObject:nil afterDelay:0];
   
    /*
    這里主要開啟了一個異步線程,再加上 使用了 dispatch_async 函數 因此
    NSLog(@"6"); 在此打印的比較隨機
     */
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"6");
    });
   
    [self test1];
   
    /*
     綜上所述:
     執(zhí)行的順序為
     test2
     test1
     NSLog(@"4");
     NSLog(@"5");
     test3
    
     NSLog(@"6"); 的出現隨機
     */

下面代碼會造成什么問題挺狰,解釋原因

- (void)viewDidLoad{
    [super viewDidLoad];
    NSLog(@"=================4");
    dispatch_sync(dispatch_get_main_queue(),
    ^{ NSLog(@"=================5"); });
    NSLog(@"=================6");
}

分析上面代碼:

viewDidLoad 在主線程中明郭, 及在dispatch_get_main_queue() 中,
執(zhí)行到sync 時 向dispatch_get_main_queue()插入 同步 threed丰泊。
sync 會等到 后面block 執(zhí)行完成才返回薯定, sync 又再 dispatch_get_main_queue() 隊列中,
它是串行隊列瞳购,sync 是后加入的话侄,
前一個是主線程,所以 sync 想執(zhí)行 block 必須等待主線程執(zhí)行完成学赛,
主線程等待 sync 返回年堆,去執(zhí)行后續(xù)內容。
照成死鎖盏浇,sync 等待mainThread 執(zhí)行完成变丧, mianThread 等待sync 函數返回。
下面例子:

- (void)viewDidLoad{
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"=================1");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"=================2"); });
        NSLog(@"=================3"); });
}
程序會完成執(zhí)行缠捌,為什么不會出現死鎖锄贷。

首先: async 在主線程中 創(chuàng)建了一個異步線程 加入 全局并發(fā)隊列,
async 不會等待block 執(zhí)行完成曼月,立即返回谊却,

1,async 立即返回哑芹, viewDidLoad 執(zhí)行完畢炎辨,及主線程執(zhí)行完畢。

2聪姿,同時碴萧,全局并發(fā)隊列立即執(zhí)行異步 block , 打印 1末购, 
當執(zhí)行到 sync 它會等待 block 執(zhí)行完成才返回破喻, 
及等待dispatch_get_main_queue() 隊列中的 mianThread 執(zhí)行完成, 然后才開始調用block 盟榴。

===Runloop===
runloop是什么曹质?在項目中有具體的應用嗎?好像沒什么可以用到的地方啊羽德?

Runloop几莽,運行循環(huán)。當我們應用啟動之后宅静,就會在主線程開啟一個運行循環(huán)章蚣,來監(jiān)聽我們的觸摸事件和消息,等姨夹。注意纤垂,這個時候,子線程中是默認不開啟運行循環(huán)的匀伏,另外洒忧,也不建議開啟蝴韭。

在項目中應用的話够颠,
1. RunLoop保證子線程的長時間存活,而不是執(zhí)行完任務后就立刻銷毀的應用場景榄鉴。這個是系統(tǒng)自己在底層自己處理得履磨。
2. 滑動與圖片刷新: 當tableview的cell上有需要從網絡獲取的圖片的時候,滾動tableView庆尘,異步線程會去加載圖片剃诅,加載完成后主線程就會設置cell的圖片,但是會造成卡頓驶忌∶可以讓設置圖片的任務在CFRunLoopDefaultMode下進行,當滾動tableView的時候付魔,RunLoop是在 UITrackingRunLoopMode 下進行聊品,不去設置圖片,而是當停止的時候几苍,再去設置圖片翻屈。

- (void)viewDidLoad {
  [super viewDidLoad];
  // 只在NSDefaultRunLoopMode下執(zhí)行(刷新圖片)
  [self.myImageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@""] afterDelay:ti inModes:@[NSDefaultRunLoopMode]];   
}
 
3. 保持子線程一直處理事件: 為了保證線程長期運轉,可以在子線程中加入RunLoop妻坝,并且給Runloop設置item伸眶,防止Runloop自動退出。


+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

+ (NSThread *)networkRequestThread {
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
        [_networkRequestThread start];
    });
    return _networkRequestThread;
}
- (void)start {
    [self.lock lock];
    if ([self isCancelled]) {
        [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    } else if ([self isReady]) {
        self.state = AFOperationExecutingState;
        [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    }
    [self.lock unlock];
}

===RunTime===
你會遇到的Runtime面試題

Objective-C 是面相運行時的語言(runtime oriented language)刽宪,就是說它會盡可能的把編譯和鏈接時要執(zhí)行的邏輯延遲到運行時厘贼。這就給了你很大的靈活性,你可以按需要把消息重定向給合適的對象圣拄,你甚 至可以交換方法的實現嘴秸,等等。

RunTime簡稱運行時。就是系統(tǒng)在運行的時候的一些機制赁遗,其中最主要的是消息機制署辉。OC的函數調用成為消息發(fā)送。屬于動態(tài)調用過程岩四。在編譯的時候并不能決定真正調用哪個函數(事實證明哭尝,在編 譯階段,OC可以調用任何函數剖煌,即使這個函數并未實現材鹦,只要申明過就不會報錯。而C語言在編譯階段就會報錯)耕姊。只有在真正運行的時候才會根據函數的名稱找 到對應的函數來調用桶唐。

以下面的代碼為例:

[obj makeText];

其中obj是一個對象,makeText是一個函數名稱茉兰。對于這樣一個簡單的調用尤泽。在編譯時RunTime會將上述代碼轉化成

objc_msgSend(obj,@selector(makeText));

首先,編譯器將代碼[obj makeText];轉化為objc_msgSend(obj, @selector (makeText));规脸,在objc_msgSend函數中坯约。首先通過obj的isa指針找到obj對應的class。在Class中先去cache中 通過SEL查找對應函數method(猜測cache中method列表是以SEL為key通過hash表來存儲的莫鸭,這樣能提高函數查找速度)闹丐,若 cache中未找到。再去methodList中查找被因,若methodlist中未找到卿拴,則取superClass中查找。若能找到梨与,則將method加 入到cache中堕花,以方便下次查找,并通過method中的函數指針跳轉到對應的函數中去執(zhí)行蛋欣。

Objective-C Runtime 是什么航徙?

Objective-C 的 Runtime 是一個運行時庫(Runtime Library),它是一個主要使用 C 和匯編寫的庫陷虎,為 C 添加了面相對象的能力并創(chuàng)造了 Objective-C到踏。這就是說它在類信息(Class information) 中被加載,完成所有的方法分發(fā)尚猿,方法轉發(fā)窝稿,等等。Objective-C runtime 創(chuàng)建了所有需要的結構體凿掂,讓 Objective-C 的面相對象編程變?yōu)榭赡堋?/p>

Method Swizzling 原理

在Objective-C中調用一個方法伴榔,其實是向一個對象發(fā)送消息纹蝴,查找消息的唯一依據是selector的名字。利用Objective-C的動態(tài)特性踪少,可以實現在運行時偷換selector對應的方法實現塘安,達到給方法掛鉤的目的。每個類都有一個方法列表援奢,存放著selector的名字和方法實現的映射關系兼犯。IMP有點類似函數指針,指向具體的Method實現集漾。

我們可以利用 method_exchangeImplementations 來交換2個方法中的IMP切黔,

我們可以利用 class_replaceMethod 來修改類,

我們可以利用 method_setImplementation 來直接設置某個方法的IMP具篇,……

歸根結底纬霞,都是偷換了selector的IMP。

基礎核心

1驱显、Objective-C對象模型及應用
2诗芜、 談Objective-C block的實現


冷門問題 沒答案自己解決

1、請解釋下method swizzling秒紧,并說出你一般什么時候會用到它绢陌?
2挨下、當一個空指針(nil pointer)調用了一個方法會發(fā)生什么熔恢?
3、為什么retainCount絕對不能用在發(fā)布的代碼中臭笆?請給出兩個相對獨立的解釋叙淌。
3、請說明一下你查找或者解決內存泄露的處理過程愁铺。這個可以深入了解面試者對內存管理方面的知識鹰霍,instruments的運用及其調試的處理過程。
4茵乱、解釋下自動回收池(autorelease pool)在程序運行時是如何運作的茂洒。
5、當處理屬性申明的時候瓶竭,原子(atomic)跟 非原子(non-atomic)屬性有什么區(qū)別督勺?
6、在C語言中斤贰,你如何能用盡可能短的時間來倒轉一個字符串智哀?
7、遍歷一個NSArray和一個NSSet荧恍,哪一個更快瓷叫?
8、解釋代碼簽名(code signing)是如何運作的。
9摹菠、Objective-C中的posing指的是什么盒卸?
10、copy跟retain有什么區(qū)別次氨?
11世落、frames跟bounds有哪些區(qū)別?
12糟需、執(zhí)行如下的代碼會發(fā)生什么情況屉佳?
Ball *ball = [[[[Ball alloc] init] autorelease] autorelease];


趣味問答

最近有沒有開發(fā)什么好玩的東西?
你最引以為豪的作品是什么洲押?
談一談你常用的開發(fā)工具都有哪些優(yōu)勢武花?
你最敬佩的獨立Mac或者iOS應用開發(fā)者是誰?
最喜歡什么項目杈帐?哪種類型的体箕?
你覺得Xcode有哪些需要改進的地方?
iOS上你最喜歡哪些API挑童?
是否有最中意的錯誤報告累铅?
你最愛以哪種方式來檢驗一項新技術是否好用?

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末站叼,一起剝皮案震驚了整個濱河市娃兽,隨后出現的幾起案子,更是在濱河造成了極大的恐慌尽楔,老刑警劉巖投储,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異阔馋,居然都是意外死亡玛荞,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進店門呕寝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來勋眯,“玉大人,你說我怎么就攤上這事下梢】吞#” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵怔球,是天一觀的道長嚼酝。 經常有香客問我,道長竟坛,這世上最難降的妖魔是什么闽巩? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任钧舌,我火速辦了婚禮,結果婚禮上涎跨,老公的妹妹穿的比我還像新娘洼冻。我一直安慰自己,他們只是感情好隅很,可當我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布撞牢。 她就那樣靜靜地躺著,像睡著了一般叔营。 火紅的嫁衣襯著肌膚如雪屋彪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天绒尊,我揣著相機與錄音畜挥,去河邊找鬼。 笑死婴谱,一個胖子當著我的面吹牛蟹但,可吹牛的內容都是我干的。 我是一名探鬼主播谭羔,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼华糖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瘟裸?” 一聲冷哼從身側響起客叉,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎景描,沒想到半個月后十办,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡超棺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了呵燕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棠绘。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖再扭,靈堂內的尸體忽然破棺而出氧苍,到底是詐尸還是另有隱情,我是刑警寧澤泛范,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布让虐,位于F島的核電站,受9級特大地震影響罢荡,放射性物質發(fā)生泄漏赡突。R本人自食惡果不足惜对扶,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惭缰。 院中可真熱鬧浪南,春花似錦、人聲如沸漱受。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昂羡。三九已至絮记,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虐先,已是汗流浹背到千。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赴穗,地道東北人憔四。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像般眉,于是被迫代替她去往敵國和親了赵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內容

  • 轉至元數據結尾創(chuàng)建: 董瀟偉甸赃,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,690評論 0 9
  • 繼上Runtime梳理(四) 通過前面的學習柿汛,我們了解到Objective-C的動態(tài)特性:Objective-C不...
    小名一峰閱讀 744評論 0 3
  • 我們常常會聽說 Objective-C 是一門動態(tài)語言,那么這個「動態(tài)」表現在哪呢埠对?我想最主要的表現就是 Obje...
    Ethan_Struggle閱讀 2,182評論 0 7
  • 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,548評論 33 466
  • 下午的陽光很刺眼络断,隔著玻璃窗,在一層淡藍色的隔離下项玛,我依然能夠感覺到太陽光的炎熱貌笨。 很多時候我都習慣了一個人的自處...
    浮生術閱讀 258評論 5 3