iOS 阿里三面 面試題整理

阿里三面面試題:

  • 1.dSYM你是如何分析的?
  • 2.多線程有哪幾種?你更傾向於哪種?
  • 3.單例弊端?
  • 4.如何把異步線程轉換成同步任務進行單元測試?
  • 5.介紹下App啓動的完成過程?
  • 6.好比App啓動過慢,你可能想到的因素有哪些?
  • 7.0x8badf00d表示是什麼?
  • 8.怎麼防止反編譯?
  • 9.說說你遇到到的技術難點?
  • 10.說說你瞭解的第三方原理或底層知識?

一、dSYM你是如何分析的

方法1 使用XCode

這種方法多是最容易的方法了。git

  1. 要使用Xcode符號化 crash log,你須要下面所列的3個文件:
  2. crash報告(.crash文件)
  3. 符號文件 (.dsymb文件)
  4. 應用程序文件 (appName.app文件,把IPA文件後綴改成zip,而後解壓,Payload目錄下的appName.app文件), 這裏的appName是你的應用程序的名稱。
  5. 把這3個文件放到同一個目錄下,打開Xcode的Window菜單下的organizer,而後點擊Devices tab,而後選中左邊的Device Logs。
  6. 而後把.crash文件拖到Device Logs或者選擇下面的import導入.crash文件。
  7. 這樣你就能夠看到crash的詳細log了。

方法2 使用命令行工具symbolicatecrash

  1. 有時候Xcode不可以很好的符號化crash文件。咱們這裏介紹如何經過symbolicatecrash來手動符號化crash log。
  2. 在處理以前,請依然將「.app「, 「.dSYM」和 ".crash"文件放到同一個目錄下。如今打開終端(Terminal)而後輸入以下的命令:
  3. export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  4. 而後輸入命令:
  5. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash appName.crash appName.app > appName.log
  6. 如今,符號化的crash log就保存在appName.log中了。

方法3 使用命令行工具atos

  1. 若是你有多個「.ipa」文件,多個".dSYMB"文件,你並不太肯定到底「dSYMB」文件對應哪一個".ipa"文件,那麼,這個方法就很是適合你。
  2. 特別當你的應用發佈到多個渠道的時候,你須要對不一樣渠道的crash文件,寫一個自動化的分析腳本的時候,這個方法就極其有用。
  3. 具體方法 請百度

本文分析了拿到用戶的.crash文件以後,如何符合化crash文件的3種方法,分別有其適用場景,方法3適用於自動化crash文件的分析。github

2.多線程有哪幾種?你更傾向於哪種?

  1. NSThread
  2. Cocoa NSOperation (使用NSOperation和NSOperationQueue)
  3. GCD (Grand Central Dispatch)

1.NSThread:(兩種建立方式)面試

[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];

NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];

[myThread start];

複製代碼

優勢:NSThread 比其餘兩個輕量級。 缺點:須要本身管理線程的生命週期,線程同步,線程同步時對數據的加鎖會有必定的系統開銷。算法

2.Cocoa Operationsql

NSOperationQueue*oprationQueue= [[NSOperationQueuealloc] init];

oprationQueueaddOperationWithBlock:^{

//這個block語句塊在子線程中執行

}
複製代碼

優勢:不須要關心線程管理,數據同步的事情。 Cocoa Operation 相關的類是 NSOperation ,NSOperationQueue。NSOperation是個抽象類,使用它必須用它的子類,能夠實現它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。建立NSOperation子類的對象,把對象添加到NSOperationQueue隊列裏執行,咱們會把咱們的執行操做放在NSOperation中main函數中。數據庫

3.GCD Grand Central Dispatch (GCD)是Apple開發的一個多核編程的解決方法,GCD是一個替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術的很高效和強大的技術。它讓程序平行排隊的特定任務,根據可用的處理資源,安排他們在任何可用的處理器核心上執行任務,一個任務能夠是一個函數(function)或者是一個block。 dispatch queue分爲下面三種: private dispatch queues,同時只執行一個任務,一般用於同步訪問特定的資源或數據。 global dispatch queue,能夠併發地執行多個任務,可是執行完成的順序是隨機的。 Main dispatch queue 它是在應用程序主線程上執行任務的。 GCD 掃盲篇;編程

三、單利的弊端

優勢: 1:一個類只被實例化一次,提供了對惟一實例的受控訪問。 2:節省系統資源 3:容許可變數目的實例。緩存

缺點: 1:一個類只有一個對象,可能形成責任太重,在必定程度上違背了「單一職責原則」。 2:因爲單利模式中沒有抽象層,所以單例類的擴展有很大的困難。 3:濫用單例將帶來一些負面問題,如爲了節省資源將數據庫鏈接池對象設計爲的單例類,可能會致使共享鏈接池對象的程序過多而出現鏈接池溢出;若是實例化的對象長時間不被利用,系統會認爲是垃圾而被回收,這將致使對象狀態的丟失。bash

四、如何把異步線程轉換成同步任務進行單元測試?

參考此篇博客 裏面的信號量的解釋,Dispatch Semaphore 信號量 在項目中的應用:強制把異步任務轉換爲同步任務來方便進行單元測試網絡

五、介紹下App啓動的完成過程?

  • ①.先加載Main函數

  • ②.在Main函數裏的 UIApplicationMain方法中,建立Application對象 建立Application的Delegate對象

  • ③.建立主循環,代理對象開始監聽事件

  • ④.啓動完畢會調用 didFinishLaunching方法,並在這個方法中建立UIWindow

  • ⑤.設置UIWindow的根控制器是誰

  • ⑥.若是有storyboard,會根據info.plist中找到應用程序的入口storyboard並加載箭頭所指的控制器

  • ⑦.顯示窗口

本文考慮的時步驟③以後到步驟⑦結束時將要調用的方法

其中有AppDelegate,ViewController,MainView(控制器的View),ChildView(子控件的View)的18個方法


AppDelegate中的:

  • 1.application:didFinishLaunchingWithOptions:

  • 2.applicationDidBecomeActive:

ViewController中的:

  • 3.loadView

  • 4.viewDidLoad

  • 5.load

  • 6.initialize

  • 7.viewWillAppear

  • 8.viewWillLayoutSubviews

  • 9.viewDidLayoutSubviews

  • 10.viewDidAppear

MainView(控制器的View)中的

  • 11.initWithCoder(若是沒有storyboard就會調用initWithFrame,這裏兩種方法視爲一種)

  • 12.awakeFromNib

  • 13.layoutSubviews

  • 14.drawRect

ChildView(子控件View)中的:

  • 15.initWithCoder(若是沒有storyboard就會調用initWithFrame,這裏兩種方法視爲一種)

  • 16.awakeFromNib

  • 17.layoutSubviews

  • 18.drawRect

那麼問題來了,不往下看你能夠把上面的十八個方法排個順序麼?

[圖片上傳失敗...(image-666d9e-1511926275309)]

+ (void)load; //這是應用程序啓動就會調用的方法,在這個方法裏寫的代碼最早調用
複製代碼
+ (void)initialize; //這個是須要用到本類時才調用,這個方法裏通常寫設置導航控制器的主題啊之類的,
//若是在後面的方法設置導航欄主題就晚了!(固然在上面的方法裏也能寫)
複製代碼
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
//這個方法裏面會建立UIWindow,設置根控制器並展示,
//好比某些應用程序要加載受權頁面也是在這加,也能夠設置觀察者,監聽到通知切換根控制器
複製代碼
ChildView - (instancetype)initWithCoder:(NSCoder *)aDecoder;
//這裏反正我是萬萬沒想到,childView的initwithcoder會在MainView的方法以前調用,
//父的都還沒出來,就先整子控件? 有了解比較透徹的博友懇請告訴我謝謝。
複製代碼
MainView - (instancetype)initWithCoder:(NSCoder *)aDecoder;
// 就是關於應用程序的數據存儲後的解檔操做。
複製代碼
MainView - (void)awakeFromNib;
//在這個方法裏設置view的背景等一系列普通操做,不要寫關於frame的還不許,
//在使用IB的時候纔會涉及到此方法的使用,當.nib文件被加載的時候,
//會發送一個awakeFromNib的消息到.nib文件中的每一個對象,
//每一個對象均可以定義本身的awakeFromNib函數來響應這個消息,執行一些必要的操做。 
複製代碼
ChildView - (void)awakeFromNib
//子控件也有本方法,重寫父類的方法。基本用法同上 
複製代碼
- (void)loadView; 
//建立視圖的層次結構,這裏須要注意,
//在沒有建立控制器的view的狀況下不能直接寫 self.view 由於self.view的底層是:
    if(_view == nil){
     _view = [self loadView]
    }
//因此這麼寫會直接形成死循環。
//若是重寫這個loadView方法裏面什麼都不寫,會顯示黑屏。
複製代碼
- (void)viewDidLoad;
//臥槽,這個方法是用的最多的方法,可是在以後的開發中就會發現愈來愈不靠譜,
//不少東西都還沒加載完畢,各類取值都不許確,不多在這裏面寫東西了。 
//這裏只是把視圖元件加載完成
複製代碼
- (void)viewWillAppear:(BOOL)animated;
//視圖將要出現,這個方法用的很是多,好比若是要設置導航欄的setNavigationBarHiden:animate: 
//就必需要在這裏寫,才能完美契合,不卡跳。 還有不少好比監聽屏幕旋轉啦,

//viewWillTransitionToSize:可能要在本方法裏再調一次,
//或者就是新到這個界面要reloadData或是自動下拉刷新等 都是寫在本方法裏
複製代碼
- (void)viewWillLayoutSubviews;
//視圖將要佈局子視圖,蘋果建議的設置界面佈局屬性的方法,
//這個方法和viewWillAppear裏,系統的底層都是沒有寫任何代碼的,也就是說這裏面不寫super 也是能夠的
複製代碼
MainView  - (void)layoutSubviews;
//在這個方法裏通常設置子控件的frame,由於這裏至關因而佈局基本完成了,
//設置時取到的frame或者是self.bounds才最準,若是在awakeFromeNib裏寫會不許確 。
//還有這裏要切記千萬不能把super layoutSubviews忘了,可能最後都很難找到這個bug
複製代碼
- (void)viewDidLayoutSubviews;
//這個方法我也是玩玩沒想到,控制器的view的子控件尚未佈局好呢,怎麼這個控制器就已經說佈局所有完成了?
//那後邊的佈局就不等了? 有獨到看法的也懇請你告訴我,這其中蘋果的意思究竟是什麼。 
複製代碼
ChildView - (void)layoutSubviews;
//控制器的子控件裏的子控件的佈局就在這裏寫了。 
複製代碼
MainView - (void)drawRect:(CGRect)rect;
//由於默認全部額UI控件都是畫上去的,在這一步就是把全部的東西畫上去,
//有時候須要用到Quartz2D的知識的時候都是在這個方法裏話,但也是要注意別忘了寫super,
//否則系統本來的東西就都畫不上來了,這裏要建議儘量使用貝塞爾路徑畫圖形,
//由於系統默認的那個上下文畫法有時可能會內存泄露。drawRect方法只能在加載時調用一次,
//若是後面還須要調用,好比下載進度的圓弧,須要一直刷幀,
//就要使用setNeedsDisplay來定時屢次調用本方法
複製代碼
ChildView - (void)drawRect:(CGRect)rect;
//view的子控件內部的畫圖方法,有時能夠本身自定義label 中間帶個刪除線的(用來寫打折前的原價) 就是在這裏畫根線 。
複製代碼
- (void)viewDidAppear:(BOOL)animated;
//把上面的畫圖都畫完了,這裏就會顯示,視圖徹底加載完成。
//在這裏的操做可能就是設置頁面的一些動畫,或者是設置tableView,collectionView,
//QQ聊天頁面啥的滾動到底部scrollToIndexPath之類的代碼操做。
複製代碼
- (void)applicationDidBecomeActive:(UIApplication *)application;
//最後這是AppDelegate的應用程序獲取焦點方法,真正到了這裏,纔是全部東西所有加載完畢,應用程序整裝待發保持最佳狀態等待用戶操做。
//這個方法中通常會寫關於彈出鍵盤的方法,好比有的用戶登陸界面爲了更好的用戶體驗,
//就讓你在剛打開程序來到登陸界面的時候,光標的焦點就自動在帳號的文本框裏閃爍,
//也就是設置帳號文本框爲第一響應者。鍵盤在頁面加載完畢後從下方彈出,這種代碼通常就在本方法寫。
複製代碼

六、好比App啓動過慢,你可能想到的因素有哪些?

1. App啓動過程
  1. 解析Info.plist
    • 加載相關信息,例如如閃屏
    • 沙箱創建、權限檢查
  2. Mach-O加載
    • 若是是胖二進制文件,尋找合適當前CPU類別的部分
    • 加載全部依賴的Mach-O文件(遞歸調用Mach-O加載的方法)
    • 定位內部、外部指針引用,例如字符串、函數等
    • 執行聲明爲__attribute__((constructor))的C函數
    • 加載類擴展(Category)中的方法
    • C++靜態對象加載、調用ObjC的 +load 函數
  3. 程序執行
    • 調用main()
    • 調用UIApplicationMain()
    • 調用applicationWillFinishLaunching
二、影響啓動性能的因素
  1. main()函數以前耗時的影響因素

    • 動態庫加載越多,啓動越慢。
    • ObjC類越多,啓動越慢
    • C的constructor函數越多,啓動越慢
    • C++靜態對象越多,啓動越慢
    • ObjC的+load越多,啓動越慢
  2. main()函數以後耗時的影響因素

    • 執行main()函數的耗時
    • 執行applicationWillFinishLaunching的耗時
    • rootViewController及其childViewController的加載、view及其subviews的加載

另外參考一下今日頭條的啓動優化方案

,針對於今日頭條這個App咱們能夠優化的點以下:

  • 純代碼方式而不是storyboard加載首頁UI。
  • 對didFinishLaunching裏的函數考慮可否挖掘能夠延遲加載或者懶加載,須要與各個業務方pm和rd共同check 對於一些已經下線的業務,刪減冗餘代碼。
  • 對於一些與UI展現無關的業務,如微博認證過時檢查、圖片最大緩存空間設置等作延遲加載。
  • 對實現了+load()方法的類進行分析,儘可能將load裏的代碼延後調用。
  • 上面統計數據顯示展現feed的導航控制器頁面(NewsListViewController)比較耗時,對於viewDidLoad以及viewWillAppear方法中儘可能去嘗試少作,晚作,不作。

七、0x8badf00d表示是什麼?

看門狗超時,在iOS上,它常常出如今執行一個同步網絡調用而阻塞主線程的狀況。所以,永遠不要進行同步網絡調用。

八、怎麼防止反編譯?

  1. 本地數據加密。
    • iOS應用防反編譯加密技術之一:對NSUserDefaults,sqlite存儲文件數據加密,保護賬號和關鍵信息
  2. URL編碼加密。
    • iOS應用防反編譯加密技術之二:對程序中出現的URL進行編碼加密,防止URL被靜態分析
  3. 網絡傳輸數據加密。
    • iOS應用防反編譯加密技術之三:對客戶端傳輸數據提供加密方案,有效防止經過網絡接口的攔截獲取數據
  4. 方法體,方法名高級混淆。
    • iOS應用防反編譯加密技術之四:對應用程序的方法名和方法體進行混淆,保證源碼被逆向後沒法解析代碼
  5. 程序結構混排加密。
    • iOS應用防反編譯加密技術之五:對應用程序邏輯結構進行打亂混排,保證源碼可讀性降到最低

其實我以爲大可沒必要,自己反編譯成本就很大,代碼這麼多,一個個反編譯過來是在蛋疼,就算有僞代碼也須要理解,並且有些代碼就算有僞代碼也很難理解。

只要作好核心代碼,作好混淆就好了,好比涉及到密碼,核心算法。

九、說說你遇到的技術難點並如何解決的?

通常這種問題的時候,面試官是想經過你講解你遇到的是什麼類型的問題,而後是怎麼解決的方案來判斷你的知識層面。值得注意的一點是,每每很多同窗在回答這道問題講如何解決的時候會說:首先經過Google、百度等搜索尋找解決方案,二、問羣裏。。。等等之類的答案。敲黑板啦~~注意啦,同窗們,人家要的不是這個答案好嗎?雖然你這麼答也不算是錯,只是理解有誤差,但起不到加分的結果。因此在面試以前,各位同窗應該好好的想一想這個問題的答案,固然每一個人遇到的難點都不大相同,涉及到的技術層面也不同,這也是這個問題的目的所在。

十、說說你瞭解的第三方原理或底層知識?

自行發揮吧!

相關文章
相關標籤/搜索