中心思想
這篇文章也是緊接著上一篇繼續(xù)歸納和總結(jié),在我們?nèi)粘5拈_發(fā)工作中,Xcode編譯器拋出的各種“無(wú)理取鬧”的異常和錯(cuò)誤。
在每個(gè)異常或錯(cuò)誤的下方,我會(huì)盡可能詳細(xì)地歸納解決辦法,解決方案中涉及網(wǎng)上取材的內(nèi)容,我會(huì)附上網(wǎng)址或者其他大神博客供大家參考。
如果文中有不當(dāng)或者錯(cuò)誤的地方,勞煩您指正,我會(huì)及時(shí)修改,以免誤導(dǎo)他人及一些iOS開發(fā)初學(xué)者。
Xcode編譯器頭疼腦熱的地方遠(yuǎn)比我們知道的要多,如果您遇到過(guò)文中不曾提及的警告或者錯(cuò)誤,并且知道如果解決它,請(qǐng)您以簡(jiǎn)信或者Email的形式發(fā)送給我(網(wǎng)頁(yè)地址欄有我的郵箱地址),我會(huì)一并總結(jié)更新,我會(huì)附上您的信息(例如博客,Github地址)。在此先謝謝了。
1.Bitcode問題
XXX does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
上面這個(gè)問題也是iOS 9SDK發(fā)布以后出現(xiàn)在Xcode7中的新問題,Bitcode是Xcode7引入的新特性,旨在為App瘦身,網(wǎng)上對(duì)它通俗的解釋是在線版安卓ART模式。
下面這段話,是親身參與2015年WWDC大會(huì)的國(guó)內(nèi)一線開發(fā)者王巍的總結(jié):Bitcode 是 LLVM 的中間碼,在編譯器更新時(shí),Apple 可以用你之前提交的 Bitcode 進(jìn)行優(yōu)化,這樣你就不必在編譯器更新后再次提交你的 app,也能享受到編譯器改進(jìn)所帶來(lái)的好處。Bitcode 支持在新項(xiàng)目中是默認(rèn)開啟的,沒有特別理由的話,你也不需要將它特意關(guān)掉。
Apple Watch應(yīng)用必須打開Bitcode,iOS沒有強(qiáng)制,但是Xcode7默認(rèn)打開了Bitcode。
解決上述問題的方法:
1.更新library使包含Bitcode,否則會(huì)出現(xiàn)以上問題,陸續(xù)都會(huì)支持Bitcode。
2.關(guān)閉Bitcode,步驟如下。
找到工程的target->build settings->直接搜索bitcode->然后在搜索結(jié)果的Build Options選項(xiàng)下找到Enable Bitcode->將YES改為NO,如下動(dòng)態(tài)圖所示。
2.升級(jí)Xcode7后上傳App時(shí)報(bào)錯(cuò)
解決方案:進(jìn)入TencentOpenApi_ios_Bundle.bunle 點(diǎn)擊顯示包內(nèi)容,把plist文件刪除即可
3.故事板與Masonry混合使用時(shí)報(bào)錯(cuò)
原因:如果用的view是storyboard連線而來(lái)的,不是自己在代碼里創(chuàng)建的。 很可能運(yùn)行的時(shí)候會(huì)報(bào)錯(cuò),說(shuō)IB已經(jīng)定義的約束和Masonry的約束沖突。即使你拖進(jìn)去控件后并沒有設(shè)置約束。
解決:按以前的方法先用故事版做好約束,然后在每個(gè)約束的屬性面板設(shè)置PlaceHolder : Remove at run time。 這樣在運(yùn)行的時(shí)候會(huì)自動(dòng)取消。
Masonry是一個(gè)Objective-C版本的第三方Autolayout庫(kù),還有一個(gè)叫做snapKit的開源庫(kù),它是Masonry的Swift版本。在Swift項(xiàng)目中,如果出現(xiàn)上述錯(cuò)誤,解決辦法同上。
4.升級(jí)Xcode7后使用JSONKit第三方庫(kù)崩潰
出現(xiàn)問題的出處是: void *keyObjectISA = *((void **)keys[idx]);這一段。這個(gè)問題我也是從網(wǎng)絡(luò)搜集的,我沒用過(guò)JSONKit,一直都是用系統(tǒng)自帶的。但是下面的解決辦法在我朋友那里得到了驗(yàn)證。如果您有異議,請(qǐng)您指正,我會(huì)及時(shí)修改。
解決辦法:將原項(xiàng)目中JSONKit.m文件替換成下面鏈接的實(shí)現(xiàn)文件即可
https://github.com/jcbertin/JSONKit
5.添加Scheme白名單
這個(gè)問題是引起一些在項(xiàng)目中使用到微信,支付寶或者微博SDK相關(guān)功能(支付,收藏,分享)出現(xiàn)錯(cuò)誤的原因,它會(huì)導(dǎo)致Xcode報(bào)如下報(bào)錯(cuò):
canOpenURL:failedforURL:“weixin://app/wxdaae92a9cfe5d54c/” - error: “This app is not allowed to query for scheme weixin”
問題描述:在iOS 9下涉及到平臺(tái)客戶端跳轉(zhuǎn),系統(tǒng)會(huì)自動(dòng)到項(xiàng)目info.plist下檢測(cè)是否設(shè)置平臺(tái)Scheme。對(duì)于需要配置的平臺(tái),如果沒有配置,就無(wú)法正常跳轉(zhuǎn)平臺(tái)客戶端。因此要支持客戶端的分享和授權(quán)等,需要配置Scheme名單。
解決辦法如下:
1)在項(xiàng)目的info.plist中添加一LSApplicationQueriesSchemes,類型為Array。
2)然后給它添加一個(gè)需要支持的項(xiàng)目,類型為字符串類型;
下面是一些項(xiàng)目中常用的白名單,你有用到的你就添加到該數(shù)組下面,類型全部為string
mqqOpensdkSSoLogin
mqzone
sinaweibo
alipayauth
alipay
safepay
mqq
mqqapi
mqqopensdkapiV3
mqqopensdkapiV2
mqqapiwallet
mqqwpa
mqqbrowser
wtloginmqq2
weixin
6. directory not found for option
問題原因:Xcode7將framworks位置改變了
解決方法:
1)點(diǎn)擊項(xiàng)目,選擇 Targets->XXXTests
2)選擇build setting 選項(xiàng),找到 Frameworks Search Path 或者 Library Search Paths
3)刪除$(SDKROOT)/Developer/Library/Frameworks,
或者使用$(PLATFORM_DIR)/Developer/Library/Frameworks替換
7.iOS 9舊狀態(tài)欄報(bào)錯(cuò)
下圖是報(bào)錯(cuò)的截圖
出錯(cuò)原因:設(shè)置app的狀態(tài)欄樣式使用了舊的方式,在info.plist里面設(shè)置了View controller-based status bar appearance為NO,默認(rèn)為YES,一般式iOS6的時(shí)候使用這種方式,iOS7,8也兼容,但是到了iOS9就報(bào)了警告。
解決辦法:
1)刪除原先編寫的代碼
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent]
2)然后在plist文件中添加項(xiàng)View controller-based status bar appearance,類型為Boolean,設(shè)置為YES(默認(rèn)是NO),如下圖7-1所示。
3)然后在你自定義的導(dǎo)航控制器里面添加如下代碼
-(UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; }
4)在模擬器上刪除應(yīng)用程序并重新運(yùn)行即可
8.大部分社交平臺(tái)接口不支持https協(xié)議。
這個(gè)問題也是上一篇中網(wǎng)絡(luò)請(qǐng)求出錯(cuò)的一個(gè)分支。目前還有大量的應(yīng)用是通過(guò)HTTP協(xié)議來(lái)訪問服務(wù)器的,而要讓所有的應(yīng)用都轉(zhuǎn)向支持HTTPS,顯然是一件耗時(shí)的工作。所以下面的方法可以一試,但只是暫時(shí)性的。畢竟蘋果幫之前提出了App Transport Security(ATS)的概念,它的提出意味著蘋果將準(zhǔn)備棄用HTTP,轉(zhuǎn)而支持HTTPS。
上述問題的解決方案就是設(shè)置域,可以簡(jiǎn)單理解成,把不支持https協(xié)議的接口設(shè)置成http的接口。
具體方法:
1)、在項(xiàng)目的info.plist中添加一個(gè)Key:NSAppTransportSecurity,類型為字典類型。
2)、然后給它添加一個(gè)NSExceptionDomains,類型為字典類型;
3)、把需要的支持的域添加給NSExceptionDomains。其中域作為Key,類型為字典類型。
4)、每個(gè)域下面需要設(shè)置3個(gè)屬性:NSIncludesSubdomains、NSExceptionRequiresForwardSecrecy、NSExceptionAllowsInsecureHTTPLoads。均為Boolean類型,值分別為YES、NO、YES。
以下文章能夠幫助你更好的理解ATS的概念
如何使用ATS提高應(yīng)用的安全性
ATS問題
App Transport Security dictionary primary keys
9.找不到.dylib文件,換成.tbd文件而又無(wú)法運(yùn)行,請(qǐng)嘗試下面的方式來(lái)解決。
拿添加libsqlite3.dylib為例(你可別照本宣科)
1)在項(xiàng)目Target中的Link Binary With Libraries 手動(dòng)添加,
首先點(diǎn)擊 “+” ;
2)顯示搜索添加頁(yè)面,在這里如果搜索之前的libsqlite3.dylib是搜不出來(lái)ios9之前的。所以需要點(diǎn)擊 Add Other,出現(xiàn)文件目錄頁(yè)面,正常情況這里也是找不到老的libsqlite3.dylib文件的,因?yàn)檫@個(gè)文件是隱藏掉的。所以需要按快捷鍵 CMD+Shift+G (Go to the folder),輸入/usr/lib后,進(jìn)入隱藏的界面;
3)然后添加你需要的 *.dylib,如libsqlite3.dylib文件.大功告成
今天先告一段落,我會(huì)繼續(xù)更新,keep moving!給廣大無(wú)聊的程序員推薦一個(gè)小游戲,我最近無(wú)聊的時(shí)候在玩,叫做okay?(你要是在改Bug,當(dāng)我沒說(shuō))。
另外給大家推薦一個(gè)bug收集工具,叫做Bugtags,我也是偶然在資深開發(fā)者唐巧的微信公眾號(hào)看見的,后來(lái)在自己的Demo中體驗(yàn)了一下,感覺小巧實(shí)用,之后還接到了一個(gè)Bugtags開發(fā)團(tuán)隊(duì)的使用情況回訪電話,就算幫助他們推廣一下。
更多有關(guān)Bugtags的內(nèi)容請(qǐng)參考以下鏈接:
Bugtags官網(wǎng)
Bugtags博客
更新兩個(gè)使用Swift語(yǔ)言出現(xiàn)的問題
1.新建playground報(bào)錯(cuò)Unable to find execution service for selected run destination
這個(gè)問題參考一下就行了
解決步驟:
1.先關(guān)閉Xcode
2.cd到Xcode所在目錄,并打開終端輸入下面兩行命令
rm-rf~/Library/Developer/CoreSimulator/Devices
killall -9 com.apple.CoreSimulator.CoreSimulatorService
關(guān)于Playground
Playground,有人將它稱呼為“訓(xùn)練場(chǎng)”,它可以讓Swift展示某些腳本語(yǔ)言的特性。實(shí)際上,Playground只是提供了一個(gè)可實(shí)時(shí)編譯運(yùn)行并展示的交互式開發(fā)環(huán)境罷了,類似于著名的REPL。它的這項(xiàng)功能完全借助于LLVM編譯器強(qiáng)大的組織能力。
目前,Playground只支持Swift語(yǔ)言,但是一位歪果仁大神開發(fā)出了一個(gè)可以運(yùn)行OC版本的Playground,有興趣可以去看看。點(diǎn)我嘍
2.dyld: Library not loaded:@rpath/libswiftCore.dylib
問題描述:真機(jī)測(cè)試時(shí),出現(xiàn)上述錯(cuò)誤
解決步驟:
1.在工程的Targets中找到Build Setting選項(xiàng)
2.搜索Embedded Content Contains Swift Code項(xiàng),將其設(shè)置為YES
第三次更新
更新兩個(gè)問題,也是在網(wǎng)上搜集的,解決辦法比較詳細(xì)
1. “Unknown class XXViewController in Interface Builder file.” 問題處理
在靜態(tài)庫(kù)中寫了一個(gè)XXViewController類,然后在主工程的xib中,將xib的類指定為XXViewController,程序運(yùn)行時(shí),報(bào)了上述錯(cuò)誤:
其實(shí)這個(gè)問題與Interface Builder無(wú)關(guān),最直接的原因還是相關(guān)的symbol沒有從靜態(tài)庫(kù)中加載進(jìn)來(lái)。這種問題的處理就是在Target的”Build Setting”–>“Other Link Flags”中加上”-all_load -ObjC”這兩個(gè)標(biāo)識(shí)位,這樣就OK了。
2.關(guān)于Unbalanced calls to begin/end appearance transitions for …問題的處理
當(dāng)某個(gè)業(yè)務(wù)有這么一個(gè)需求,進(jìn)入一個(gè)列表后需要立馬又push一個(gè)web頁(yè)面,做一些活動(dòng)的推廣。在iOS 8上,我們的實(shí)現(xiàn)是一切OK的;但到了iOS 7上,就發(fā)現(xiàn)這個(gè)web頁(yè)面push不出來(lái)了,同時(shí)控制臺(tái)給了一條警告消息,即如下:
Unbalanced calls to begin/end appearance transitions for ...
在這種情況下,點(diǎn)擊導(dǎo)航欄中的返回按鈕時(shí),直接顯示一個(gè)黑屏。
我們到stackoverflow上查了一下,有這么一段提示:
occurs when you try and display a new viewcontroller before the current view controller is finished displaying.
意思是說(shuō)在當(dāng)前視圖控制器完成顯示之前,又試圖去顯示一個(gè)新的視圖控制器。
于是我們?nèi)ヅ挪榇a,果然發(fā)現(xiàn),在viewDidLoad里面去做了次網(wǎng)絡(luò)請(qǐng)求操作,且請(qǐng)求返回后就去push這個(gè)web活動(dòng)推廣頁(yè)。此時(shí),當(dāng)前的視圖控制器可能并未顯示完成(即未完成push操作)。
Basically you are trying to push two view controllers onto the stack at almost the same time.
解釋如下:
當(dāng)幾乎同時(shí)將兩個(gè)視圖控制器push到當(dāng)前的導(dǎo)航控制器棧中時(shí),或者同時(shí)pop兩個(gè)不同的視圖控制器,就會(huì)出現(xiàn)不確定的結(jié)果。所以我們應(yīng)該確保同一時(shí)間,對(duì)同一個(gè)導(dǎo)航控制器棧只有一個(gè)操作,即便當(dāng)前的視圖控制器正在動(dòng)畫過(guò)程中,也不應(yīng)該再去push或pop一個(gè)新的視圖控制器。
所以最后我們把web活動(dòng)的數(shù)據(jù)請(qǐng)求放到了viewDidAppear里面,并做了些處理,這樣問題就解決了。
原文鏈接
第四次更新
1.手動(dòng)performSegueWithIdentifier沒有生效的問題
這個(gè)問題是因?yàn)閷?duì)視圖控制對(duì)象的生命周期概念沒有深刻理解,比如說(shuō)當(dāng)用戶打開應(yīng)用,判斷用戶是否登陸,如果未登陸,就跳轉(zhuǎn)到登錄頁(yè)面這個(gè)情況。
如果你將判斷用戶是否登陸的語(yǔ)句放到了視圖的viewDidLoad中去,那么這個(gè)方法是不會(huì)生效的。因?yàn)樵趘iewDidLoad中就啟動(dòng)segue的話,依然會(huì)被后來(lái)填充的視圖覆蓋,要是在視圖加載完成后的viewDidAppear中啟動(dòng)segue,就不會(huì)出現(xiàn)錯(cuò)誤了。