1、dSYM你是如何分析的
方法1 使用XCode
這種方法可能是最容易的方法了。
要使用Xcode符號(hào)化 crash log塔橡,你需要下面所列的3個(gè)文件:
crash報(bào)告(.crash文件)
符號(hào)文件 (.dsymb文件)
應(yīng)用程序文件 (appName.app文件佳镜,把IPA文件后綴改為zip,然后解壓姊氓,Payload目錄下的appName.app文件), 這里的appName是你的應(yīng)用程序的名稱(chēng)丐怯。
把這3個(gè)文件放到同一個(gè)目錄下,打開(kāi)Xcode的Window菜單下的organizer翔横,然后點(diǎn)擊Devices tab读跷,然后選中左邊的Device Logs。
然后把.crash文件拖到Device Logs或者選擇下面的import導(dǎo)入.crash文件禾唁。
這樣你就可以看到crash的詳細(xì)log了效览。
方法2 使用命令行工具symbolicatecrash
有時(shí)候Xcode不能夠很好的符號(hào)化crash文件。我們這里介紹如何通過(guò)symbolicatecrash來(lái)手動(dòng)符號(hào)化crash log荡短。
在處理之前丐枉,請(qǐng)依然將“.app“, “.dSYM”和 ".crash"文件放到同一個(gè)目錄下。現(xiàn)在打開(kāi)終端(Terminal)然后輸入如下的命令:
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
然后輸入命令:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash appName.crash appName.app > appName.log
現(xiàn)在掘托,符號(hào)化的crash log就保存在appName.log中了瘦锹。
方法3 使用命令行工具atos
如果你有多個(gè)“.ipa”文件,多個(gè)".dSYMB"文件闪盔,你并不太確定到底“dSYMB”文件對(duì)應(yīng)哪個(gè)".ipa"文件弯院,那么,這個(gè)方法就非常適合你泪掀。
特別當(dāng)你的應(yīng)用發(fā)布到多個(gè)渠道的時(shí)候听绳,你需要對(duì)不同渠道的crash文件,寫(xiě)一個(gè)自動(dòng)化的分析腳本的時(shí)候异赫,這個(gè)方法就極其有用椅挣。
具體方法 請(qǐng)百度
本文分析了拿到用戶(hù)的.crash文件之后,如何符合化crash文件的3種方法祝辣,分別有其適用場(chǎng)景贴妻,方法3適用于自動(dòng)化crash文件的分析。
2.多線程有哪幾種蝙斜?你更傾向于哪一種名惩?
NSThread Cocoa NSOperation (使用NSOperation和NSOperationQueue) GCD (Grand Central Dispatch)
1.NSThread:(兩種創(chuàng)建方式)
[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];
[myThread start];
優(yōu)點(diǎn):NSThread 比其他兩個(gè)輕量級(jí)。 缺點(diǎn):需要自己管理線程的生命周期孕荠,線程同步娩鹉,線程同步時(shí)對(duì)數(shù)據(jù)的加鎖會(huì)有一定的系統(tǒng)開(kāi)銷(xiāo)攻谁。
2.Cocoa Operation
NSOperationQueue*oprationQueue= [[NSOperationQueuealloc] init];
oprationQueueaddOperationWithBlock:^{
//這個(gè)block語(yǔ)句塊在子線程中執(zhí)行
}
優(yōu)點(diǎn):不需要關(guān)心線程管理,數(shù)據(jù)同步的事情弯予。 Cocoa Operation 相關(guān)的類(lèi)是 NSOperation 戚宦,NSOperationQueue。NSOperation是個(gè)抽象類(lèi)锈嫩,使用它必須用它的子類(lèi)受楼,可以實(shí)現(xiàn)它或者使用它定義好的兩個(gè)子類(lèi):NSInvocationOperation 和 NSBlockOperation。創(chuàng)建NSOperation子類(lèi)的對(duì)象呼寸,把對(duì)象添加到NSOperationQueue隊(duì)列里執(zhí)行艳汽,我們會(huì)把我們的執(zhí)行操作放在NSOperation中main函數(shù)中。
3.GCD
Grand Central Dispatch (GCD)是Apple開(kāi)發(fā)的一個(gè)多核編程的解決方法对雪,GCD是一個(gè)替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術(shù)的很高效和強(qiáng)大的技術(shù)河狐。它讓程序平行排隊(duì)的特定任務(wù),根據(jù)可用的處理資源瑟捣,安排他們?cè)谌魏慰捎玫奶幚砥骱诵纳蠄?zhí)行任務(wù)馋艺,一個(gè)任務(wù)可以是一個(gè)函數(shù)(function)或者是一個(gè)block。 dispatch queue分為下面三種: private dispatch queues迈套,同時(shí)只執(zhí)行一個(gè)任務(wù)捐祠,通常用于同步訪問(wèn)特定的資源或數(shù)據(jù)。 global dispatch queue交汤,可以并發(fā)地執(zhí)行多個(gè)任務(wù)雏赦,但是執(zhí)行完成的順序是隨機(jī)的。 Main dispatch queue 它是在應(yīng)用程序主線程上執(zhí)行任務(wù)的芙扎。 GCD 掃盲篇;
3、單利的弊端
優(yōu)點(diǎn):
1:一個(gè)類(lèi)只被實(shí)例化一次填大,提供了對(duì)唯一實(shí)例的受控訪問(wèn)戒洼。
2:節(jié)省系統(tǒng)資源
3:允許可變數(shù)目的實(shí)例。
缺點(diǎn):
1:一個(gè)類(lèi)只有一個(gè)對(duì)象允华,可能造成責(zé)任過(guò)重圈浇,在一定程度上違背了“單一職責(zé)原則”。
2:由于單利模式中沒(méi)有抽象層靴寂,因此單例類(lèi)的擴(kuò)展有很大的困難磷蜀。
3:濫用單例將帶來(lái)一些負(fù)面問(wèn)題,如為了節(jié)省資源將數(shù)據(jù)庫(kù)連接池對(duì)象設(shè)計(jì)為的單例類(lèi)百炬,可能會(huì)導(dǎo)致共享連接池對(duì)象的程序過(guò)多而出現(xiàn)連接池溢出褐隆;如果實(shí)例化的對(duì)象長(zhǎng)時(shí)間不被利用,系統(tǒng)會(huì)認(rèn)為是垃圾而被回收剖踊,這將導(dǎo)致對(duì)象狀態(tài)的丟失庶弃。
4衫贬、如何把異步線程轉(zhuǎn)換成同步任務(wù)進(jìn)行單元測(cè)試?
參考此篇博客 里面的信號(hào)量的解釋?zhuān)珼ispatch Semaphore 信號(hào)量 在項(xiàng)目中的應(yīng)用:強(qiáng)制把異步任務(wù)轉(zhuǎn)換為同步任務(wù)來(lái)方便進(jìn)行單元測(cè)試
5歇攻、介紹下App啟動(dòng)的完成過(guò)程固惯?
①.先加載Main函數(shù)
②.在Main函數(shù)里的 UIApplicationMain方法中,創(chuàng)建Application對(duì)象 創(chuàng)建Application的Delegate對(duì)象
③.創(chuàng)建主循環(huán)缴守,代理對(duì)象開(kāi)始監(jiān)聽(tīng)事件
④.啟動(dòng)完畢會(huì)調(diào)用 didFinishLaunching方法葬毫,并在這個(gè)方法中創(chuàng)建UIWindow
⑤.設(shè)置UIWindow的根控制器是誰(shuí)
⑥.如果有storyboard,會(huì)根據(jù)info.plist中找到應(yīng)用程序的入口storyboard并加載箭頭所指的控制器
⑦.顯示窗口
本文考慮的時(shí)步驟③之后到步驟⑦結(jié)束時(shí)將要調(diào)用的方法
其中有AppDelegate,ViewController,MainView(控制器的View),ChildView(子控件的View)的18個(gè)方法
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(如果沒(méi)有storyboard就會(huì)調(diào)用initWithFrame屡穗,這里兩種方法視為一種)
12.awakeFromNib
13.layoutSubviews
14.drawRect
ChildView(子控件View)中的:
15.initWithCoder(如果沒(méi)有storyboard就會(huì)調(diào)用initWithFrame贴捡,這里兩種方法視為一種)
16.awakeFromNib
17.layoutSubviews
18.drawRect
那么問(wèn)題來(lái)了,不往下看你可以把上面的十八個(gè)方法排個(gè)順序么鸡捐?
- (void)load; //這是應(yīng)用程序啟動(dòng)就會(huì)調(diào)用的方法栈暇,在這個(gè)方法里寫(xiě)的代碼最先調(diào)用
- (void)initialize; //這個(gè)是需要用到本類(lèi)時(shí)才調(diào)用,這個(gè)方法里一般寫(xiě)設(shè)置導(dǎo)航控制器的主題啊之類(lèi)的箍镜,
//如果在后面的方法設(shè)置導(dǎo)航欄主題就晚了T雌怼(當(dāng)然在上面的方法里也能寫(xiě))
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
//這個(gè)方法里面會(huì)創(chuàng)建UIWindow,設(shè)置根控制器并展現(xiàn)色迂,
//比如某些應(yīng)用程序要加載授權(quán)頁(yè)面也是在這加香缺,也可以設(shè)置觀察者,監(jiān)聽(tīng)到通知切換根控制器
ChildView - (instancetype)initWithCoder:(NSCoder *)aDecoder;
//這里反正我是萬(wàn)萬(wàn)沒(méi)想到歇僧,childView的initwithcoder會(huì)在MainView的方法之前調(diào)用图张,
//父的都還沒(méi)出來(lái),就先整子控件诈悍? 有了解比較透徹的博友懇請(qǐng)告訴我謝謝祸轮。
MainView - (instancetype)initWithCoder:(NSCoder *)aDecoder;
// 就是關(guān)于應(yīng)用程序的數(shù)據(jù)存儲(chǔ)后的解檔操作。
MainView - (void)awakeFromNib;
//在這個(gè)方法里設(shè)置view的背景等一系列普通操作侥钳,不要寫(xiě)關(guān)于frame的還不準(zhǔn)适袜,
//在使用IB的時(shí)候才會(huì)涉及到此方法的使用,當(dāng).nib文件被加載的時(shí)候舷夺,
//會(huì)發(fā)送一個(gè)awakeFromNib的消息到.nib文件中的每個(gè)對(duì)象苦酱,
//每個(gè)對(duì)象都可以定義自己的awakeFromNib函數(shù)來(lái)響應(yīng)這個(gè)消息,執(zhí)行一些必要的操作给猾。
ChildView - (void)awakeFromNib
//子控件也有本方法疫萤,重寫(xiě)父類(lèi)的方法「疑欤基本用法同上 - (void)loadView;
//創(chuàng)建視圖的層次結(jié)構(gòu)扯饶,這里需要注意,
//在沒(méi)有創(chuàng)建控制器的view的情況下不能直接寫(xiě) self.view 因?yàn)閟elf.view的底層是:
if(_view == nil){
_view = [self loadView]
}
//所以這么寫(xiě)會(huì)直接造成死循環(huán)。
//如果重寫(xiě)這個(gè)loadView方法里面什么都不寫(xiě)帝际,會(huì)顯示黑屏蔓同。 - (void)viewDidLoad;
//臥槽,這個(gè)方法是用的最多的方法蹲诀,但是在之后的開(kāi)發(fā)中就會(huì)發(fā)現(xiàn)越來(lái)越不靠譜斑粱,
//很多東西都還沒(méi)加載完畢,各種取值都不準(zhǔn)確脯爪,很少在這里面寫(xiě)東西了则北。
//這里只是把視圖元件加載完成 - (void)viewWillAppear:(BOOL)animated;
//視圖將要出現(xiàn),這個(gè)方法用的非常多痕慢,比如如果要設(shè)置導(dǎo)航欄的setNavigationBarHiden:animate:
//就必須要在這里寫(xiě)尚揣,才能完美契合,不卡跳掖举。 還有很多比如監(jiān)聽(tīng)屏幕旋轉(zhuǎn)啦快骗,
//viewWillTransitionToSize:可能要在本方法里再調(diào)一次,
//或者就是新到這個(gè)界面要reloadData或是自動(dòng)下拉刷新等 都是寫(xiě)在本方法里
- (void)viewWillLayoutSubviews;
//視圖將要布局子視圖塔次,蘋(píng)果建議的設(shè)置界面布局屬性的方法方篮,
//這個(gè)方法和viewWillAppear里,系統(tǒng)的底層都是沒(méi)有寫(xiě)任何代碼的励负,也就是說(shuō)這里面不寫(xiě)super 也是可以的
MainView - (void)layoutSubviews;
//在這個(gè)方法里一般設(shè)置子控件的frame藕溅,因?yàn)檫@里相當(dāng)于是布局基本完成了,
//設(shè)置時(shí)取到的frame或者是self.bounds才最準(zhǔn)继榆,如果在awakeFromeNib里寫(xiě)會(huì)不準(zhǔn)確 巾表。
//還有這里要切記千萬(wàn)不能把super layoutSubviews忘了,可能最后都很難找到這個(gè)bug - (void)viewDidLayoutSubviews;
//這個(gè)方法我也是玩玩沒(méi)想到略吨,控制器的view的子控件還沒(méi)有布局好呢集币,怎么這個(gè)控制器就已經(jīng)說(shuō)布局全部完成了?
//那后邊的布局就不等了翠忠? 有獨(dú)到見(jiàn)解的也懇請(qǐng)你告訴我惠猿,這其中蘋(píng)果的意思到底是什么。
ChildView - (void)layoutSubviews;
//控制器的子控件里的子控件的布局就在這里寫(xiě)了负间。
MainView - (void)drawRect:(CGRect)rect;
//因?yàn)槟J(rèn)所有額UI控件都是畫(huà)上去的,在這一步就是把所有的東西畫(huà)上去姜凄,
//有時(shí)候需要用到Quartz2D的知識(shí)的時(shí)候都是在這個(gè)方法里話(huà)政溃,但也是要注意別忘了寫(xiě)super,
//不然系統(tǒng)原本的東西就都畫(huà)不上來(lái)了态秧,這里要建議盡可能使用貝塞爾路徑畫(huà)圖形董虱,
//因?yàn)橄到y(tǒng)默認(rèn)的那個(gè)上下文畫(huà)法有時(shí)可能會(huì)內(nèi)存泄露。drawRect方法只能在加載時(shí)調(diào)用一次,
//如果后面還需要調(diào)用愤诱,比如下載進(jìn)度的圓弧云头,需要一直刷幀,
//就要使用setNeedsDisplay來(lái)定時(shí)多次調(diào)用本方法
ChildView - (void)drawRect:(CGRect)rect;
//view的子控件內(nèi)部的畫(huà)圖方法淫半,有時(shí)可以自己自定義label 中間帶個(gè)刪除線的(用來(lái)寫(xiě)打折前的原價(jià)) 就是在這里畫(huà)根線 溃槐。 - (void)viewDidAppear:(BOOL)animated;
//把上面的畫(huà)圖都畫(huà)完了,這里就會(huì)顯示科吭,視圖完全加載完成昏滴。
//在這里的操作可能就是設(shè)置頁(yè)面的一些動(dòng)畫(huà),或者是設(shè)置tableView,collectionView对人,
//QQ聊天頁(yè)面啥的滾動(dòng)到底部scrollToIndexPath之類(lèi)的代碼操作谣殊。 - (void)applicationDidBecomeActive:(UIApplication *)application;
//最后這是AppDelegate的應(yīng)用程序獲取焦點(diǎn)方法,真正到了這里牺弄,才是所有東西全部加載完畢姻几,應(yīng)用程序整裝待發(fā)保持最佳狀態(tài)等待用戶(hù)操作。
//這個(gè)方法中一般會(huì)寫(xiě)關(guān)于彈出鍵盤(pán)的方法势告,比如有的用戶(hù)登錄界面為了更好的用戶(hù)體驗(yàn)蛇捌,
//就讓你在剛打開(kāi)程序來(lái)到登錄界面的時(shí)候,光標(biāo)的焦點(diǎn)就自動(dòng)在賬號(hào)的文本框里閃爍培慌,
//也就是設(shè)置賬號(hào)文本框?yàn)榈谝豁憫?yīng)者豁陆。鍵盤(pán)在頁(yè)面加載完畢后從下方彈出,這種代碼一般就在本方法寫(xiě)吵护。
6盒音、比如App啟動(dòng)過(guò)慢,你可能想到的因素有哪些馅而?
- App啟動(dòng)過(guò)程
解析Info.plist
加載相關(guān)信息祥诽,例如如閃屏
沙箱建立、權(quán)限檢查
Mach-O加載
如果是胖二進(jìn)制文件瓮恭,尋找合適當(dāng)前CPU類(lèi)別的部分
加載所有依賴(lài)的Mach-O文件(遞歸調(diào)用Mach-O加載的方法)
定位內(nèi)部雄坪、外部指針引用,例如字符串屯蹦、函數(shù)等
執(zhí)行聲明為attribute((constructor))的C函數(shù)
加載類(lèi)擴(kuò)展(Category)中的方法
C++靜態(tài)對(duì)象加載维哈、調(diào)用ObjC的 +load 函數(shù)
程序執(zhí)行
調(diào)用main()
調(diào)用UIApplicationMain()
調(diào)用applicationWillFinishLaunching
2、影響啟動(dòng)性能的因素
main()函數(shù)之前耗時(shí)的影響因素
動(dòng)態(tài)庫(kù)加載越多登澜,啟動(dòng)越慢阔挠。
ObjC類(lèi)越多,啟動(dòng)越慢
C的constructor函數(shù)越多脑蠕,啟動(dòng)越慢
C++靜態(tài)對(duì)象越多购撼,啟動(dòng)越慢
ObjC的+load越多跪削,啟動(dòng)越慢
main()函數(shù)之后耗時(shí)的影響因素
執(zhí)行main()函數(shù)的耗時(shí)
執(zhí)行applicationWillFinishLaunching的耗時(shí)
rootViewController及其childViewController的加載、view及其subviews的加載
另外參考一下今日頭條的啟動(dòng)優(yōu)化方案
針對(duì)于今日頭條這個(gè)App我們可以?xún)?yōu)化的點(diǎn)如下:
純代碼方式而不是storyboard加載首頁(yè)UI迂求。
對(duì)didFinishLaunching里的函數(shù)考慮能否挖掘可以延遲加載或者懶加載碾盐,需要與各個(gè)業(yè)務(wù)方pm和rd共同check 對(duì)于一些已經(jīng)下線的業(yè)務(wù),刪減冗余代碼揩局。
對(duì)于一些與UI展示無(wú)關(guān)的業(yè)務(wù)毫玖,如微博認(rèn)證過(guò)期檢查、圖片最大緩存空間設(shè)置等做延遲加載谐腰。
對(duì)實(shí)現(xiàn)了+load()方法的類(lèi)進(jìn)行分析孕豹,盡量將load里的代碼延后調(diào)用。
上面統(tǒng)計(jì)數(shù)據(jù)顯示展示feed的導(dǎo)航控制器頁(yè)面(NewsListViewController)比較耗時(shí)十气,對(duì)于viewDidLoad以及viewWillAppear方法中盡量去嘗試少做励背,晚做,不做砸西。
7叶眉、0x8badf00d表示是什么?
看門(mén)狗超時(shí)芹枷,在iOS上衅疙,它經(jīng)常出現(xiàn)在執(zhí)行一個(gè)同步網(wǎng)絡(luò)調(diào)用而阻塞主線程的情況。因此鸳慈,永遠(yuǎn)不要進(jìn)行同步網(wǎng)絡(luò)調(diào)用饱溢。
8、怎么防止反編譯走芋?
本地?cái)?shù)據(jù)加密绩郎。
iOS應(yīng)用防反編譯加密技術(shù)之一:對(duì)NSUserDefaults,sqlite存儲(chǔ)文件數(shù)據(jù)加密翁逞,保護(hù)帳號(hào)和關(guān)鍵信息
URL編碼加密肋杖。
iOS應(yīng)用防反編譯加密技術(shù)之二:對(duì)程序中出現(xiàn)的URL進(jìn)行編碼加密,防止URL被靜態(tài)分析
網(wǎng)絡(luò)傳輸數(shù)據(jù)加密挖函。
iOS應(yīng)用防反編譯加密技術(shù)之三:對(duì)客戶(hù)端傳輸數(shù)據(jù)提供加密方案状植,有效防止通過(guò)網(wǎng)絡(luò)接口的攔截獲取數(shù)據(jù)
方法體,方法名高級(jí)混淆怨喘。
iOS應(yīng)用防反編譯加密技術(shù)之四:對(duì)應(yīng)用程序的方法名和方法體進(jìn)行混淆津畸,保證源碼被逆向后無(wú)法解析代碼
程序結(jié)構(gòu)混排加密。
iOS應(yīng)用防反編譯加密技術(shù)之五:對(duì)應(yīng)用程序邏輯結(jié)構(gòu)進(jìn)行打亂混排必怜,保證源碼可讀性降到最低
其實(shí)我覺(jué)得大可不必洼畅,本身反編譯成本就很大,代碼這么多棚赔,一個(gè)個(gè)反編譯過(guò)來(lái)是在蛋疼,就算有偽代碼也需要理解,而且有些代碼就算有偽代碼也很難理解靠益。
只要做好核心代碼丧肴,做好混淆就行了,比如涉及到密碼胧后,核心算法芋浮。
9、說(shuō)說(shuō)你遇到的技術(shù)難點(diǎn)并如何解決的壳快?
一般這種問(wèn)題的時(shí)候纸巷,面試官是想通過(guò)你講解你遇到的是什么類(lèi)型的問(wèn)題,然后是怎么解決的方案來(lái)判斷你的知識(shí)層面眶痰。值得注意的一點(diǎn)是瘤旨,往往不少同學(xué)在回答這道問(wèn)題講如何解決的時(shí)候會(huì)說(shuō):首先通過(guò)Google、百度等搜索尋找解決方案竖伯,2存哲、問(wèn)群里。七婴。祟偷。等等之類(lèi)的答案。敲黑板啦~~注意啦打厘,同學(xué)們修肠,人家要的不是這個(gè)答案好嗎?雖然你這么答也不算是錯(cuò)户盯,只是理解有偏差嵌施,但起不到加分的結(jié)果。所以在面試之前先舷,各位同學(xué)應(yīng)該好好的想想這個(gè)問(wèn)題的答案艰管,當(dāng)然每個(gè)人遇到的難點(diǎn)都不大相同,涉及到的技術(shù)層面也不一樣蒋川,這也是這個(gè)問(wèn)題的目的所在牲芋。
10、說(shuō)說(shuō)你了解的第三方原理或底層知識(shí)捺球?
作為一個(gè)開(kāi)發(fā)者缸浦,有一個(gè)學(xué)習(xí)的氛圍和一個(gè)交流圈子特別重要,這是我的交流群(123)氮兵,大家有興趣可以進(jìn)群里一起交流學(xué)習(xí)
另附上一份大廠面試題合集裂逐,進(jìn)群可自行下載!