參考:Clang Diagnostics
談?wù)凮bjective-C的警告
iOS警告收錄及科學(xué)快速的消除方法
一艘希、什么是Clang Diagnostics硼身?
診斷是結(jié)合了邏輯與分析來(lái)得出的一個(gè)結(jié)論。
在醫(yī)學(xué)界覆享,診斷是通過(guò)實(shí)驗(yàn)室樣本做后盾的本能來(lái)判斷佳遂。而對(duì)于工業(yè)制造,則是通過(guò)在統(tǒng)計(jì)和方向都等同應(yīng)用來(lái)診斷產(chǎn)品故障撒顿。
對(duì)于我們開(kāi)發(fā)者來(lái)說(shuō)丑罪,我們通過(guò)代碼通知后續(xù)代碼的生產(chǎn),創(chuàng)建了一個(gè)在過(guò)去半個(gè)世紀(jì)里呈幾何倍數(shù)發(fā)展的技術(shù)的正反饋循環(huán)。尤其對(duì)于我們的OC的開(kāi)發(fā)者來(lái)說(shuō)吩屹,最有效的診斷來(lái)自Clang跪另。
二、OC中常用的代碼診斷
1煤搜、當(dāng)你在 XCode 中運(yùn)行 "Build & Analyze" (??B) 后得到的驚人結(jié)果免绿,就是Clang的代碼診斷
這個(gè)命令是簡(jiǎn)單的邏輯診斷,會(huì)診斷出簡(jiǎn)單的邏輯錯(cuò)誤擦盾,比如下圖嘲驾,就診斷出imageArray初始化之后沒(méi)有用。經(jīng)常用這個(gè)命令可以避免很多基本的代碼邏輯錯(cuò)誤迹卢。
2距淫、如果你想在編程的過(guò)程中開(kāi)啟困難模式,你只要設(shè)置設(shè)置 -Weverything 標(biāo)志婶希,并在你的編譯設(shè)置中勾選上 "Treat Warnings as Errors"榕暇。
一個(gè)有節(jié)操的程序員會(huì)在乎自己的代碼的警告,就像在乎飯碗邊上有只死蟑螂那樣喻杈。 ——@onevcat
編譯器給出的警告對(duì)開(kāi)發(fā)者開(kāi)說(shuō)是很有用的信息彤枢。警告不會(huì)阻止繼續(xù)編譯和鏈接,也不會(huì)導(dǎo)致程序不能運(yùn)行筒饰,但是很多時(shí)候缴啡,編譯器會(huì)先你一步發(fā)現(xiàn)問(wèn)題所在,對(duì)于OC來(lái)更是如此瓷们。Clang不僅對(duì)于明顯的錯(cuò)誤能夠提出警告(比如某個(gè)方法或者接口未實(shí)現(xiàn))业栅,也能對(duì)很多潛在的可能的問(wèn)題作出提示(比如說(shuō)方法已經(jīng)廢棄,或者有問(wèn)題的轉(zhuǎn)換)谬晕,而這些在很多時(shí)候都可能成為潛在的致命錯(cuò)誤碘裕,必須加以重視。
像Ruby或者PHP這樣的動(dòng)態(tài)語(yǔ)言沒(méi)有所謂的編譯警告攒钳,而C#或者Java這類(lèi)語(yǔ)言的警告很多都是不得不照顧的廢棄方法什么的帮孔,很多開(kāi)發(fā)者已經(jīng)習(xí)慣于忽略警告進(jìn)行開(kāi)發(fā)。OC由于現(xiàn)在由蘋(píng)果負(fù)責(zé)維護(hù)不撑,Clang的LLVM也同時(shí)是蘋(píng)果在做文兢,可以說(shuō)從語(yǔ)言到編譯器到SDK全局都在掌握之中,因此做OC開(kāi)發(fā)時(shí)的警告往往比其他語(yǔ)言的警告更有參考價(jià)值焕檬。打開(kāi)盡可能多的警告提示姆坚,并且在程序開(kāi)發(fā)中盡量避免生成警告,對(duì)于構(gòu)建一個(gè)健壯高效的程序來(lái)說(shuō)实愚,是必須的兼呵。
當(dāng)然在UI里一個(gè)一個(gè)點(diǎn)擊激活警告雖然簡(jiǎn)單兔辅,但每次都這樣來(lái)一回是一種一點(diǎn)也不有趣的做法,特別是在你已經(jīng)了解它們的內(nèi)容并決定打開(kāi)它們的時(shí)候萍程。在編譯選項(xiàng)中加入合適的flag能夠打開(kāi)或者關(guān)閉警告:在
Build Setting
中的Other C Flags
里添加形似-W...
的編譯標(biāo)識(shí)幢妄。你可以在其中填寫(xiě)任意多的-W...
以開(kāi)關(guān)某些警告,比如茫负,填寫(xiě)為-Wall -Wno-unused-variable
即可打開(kāi)“全部”警告(其實(shí)并不是全部蕉鸳,只是一大部分嚴(yán)重警告而已),但是不啟用“未使用變量”的警告忍法。使用-W...`的形式潮尝,而不是在UI上勾選的一大好處是,在編譯器版本更新時(shí)饿序,新加入的警告如果包含在-Wall中的話勉失,不需要對(duì)工程做任何修改,新的警告即可以生效原探。這樣立即可以察覺(jué)到同一個(gè)工程由于編譯器版本更新時(shí)可能帶來(lái)的隱患乱凿。另外一個(gè)更重要的原因是..Xcode的UI并沒(méi)有提供所有的警告 =_=
可以看見(jiàn),使用了這個(gè)flag之后咽弦,我的警告數(shù)從234徒蟆,迅速飆升到999+。型型。段审。
剛才提到的,需要注意的是闹蒜,-Wall
的名字雖然是all寺枉,但是這真的只是一個(gè)迷惑人的詞語(yǔ),實(shí)際上-Wall
涵蓋的僅只是所有警告中的一個(gè)子集绷落。在StackExchange上有一個(gè)在Google工作的Clang開(kāi)發(fā)者進(jìn)行的回答姥闪,其中解釋了有一些重要的警告組:
Wall
并不是所有警告。這一個(gè)警告組開(kāi)啟的是編譯器開(kāi)發(fā)者對(duì)于“你所寫(xiě)的代碼中有問(wèn)題”這一命題有著很高的自信的那些警告嘱函。要是在這一組設(shè)定下你的代碼出現(xiàn)了警告甘畅,那基本上就是你的代碼真的存在嚴(yán)重問(wèn)題了。但是同時(shí)往弓,并不是說(shuō)打開(kāi)Wall
就萬(wàn)事大吉了,因?yàn)?code>Wall所針對(duì)的僅僅只是經(jīng)典代碼庫(kù)中的為數(shù)不多的問(wèn)題蓄氧,因此有一些致命的警告并不能被其捕捉到函似。但是不論如何,因?yàn)閃all的警告提供的都是可信度和優(yōu)先級(jí)很高的警告喉童,所以為所有項(xiàng)目(至少是所有新項(xiàng)目)打開(kāi)這組警告撇寞,應(yīng)該成為一種良好的習(xí)慣。Wextra
如其所名,-Wextra
組提供“額外的”警告蔑担。這個(gè)組和-Wall
組幾乎一樣有用牌废,但是有些情況下對(duì)于代碼相對(duì)過(guò)于嚴(yán)苛。一個(gè)很常見(jiàn)的例子是啤握,-Wextra
中包含了-Wsign-compare
鸟缕,這個(gè)警告標(biāo)識(shí)會(huì)開(kāi)啟比較時(shí)候?qū)igned和unsigned的類(lèi)型檢查,當(dāng)比較符兩邊一邊是signed一邊是unsigned時(shí)排抬,產(chǎn)生警告懂从。其實(shí)很多代碼并沒(méi)有特別在意這樣的比較,而且絕大多數(shù)時(shí)候蹲蒲,比較signed和unsigned也是沒(méi)有太大問(wèn)題的(當(dāng)然不排除會(huì)有致命錯(cuò)誤出現(xiàn)的情況)番甩。需要注意,-Wextra
和-Wall
是相互獨(dú)立的兩個(gè)警告組届搁,雖然里面打開(kāi)的警告標(biāo)識(shí)有個(gè)別是重復(fù)的缘薛,但是兩組并沒(méi)有包含的關(guān)系。想要同時(shí)使用的話必須在Other C Flags中都加上Weverything
這個(gè)是真正的所有警告卡睦。但是一般開(kāi)發(fā)者不會(huì)選擇使用這個(gè)標(biāo)識(shí)宴胧,因?yàn)樗四切┻€正在開(kāi)發(fā)中的可能尚存bug的警告提示。這個(gè)標(biāo)識(shí)一般是編譯器開(kāi)發(fā)者用來(lái)調(diào)試時(shí)使用的么翰,如果你想在自己的項(xiàng)目里開(kāi)啟的話牺汤,警告一定會(huì)爆棚導(dǎo)致你想開(kāi)始撞墻..
3、控制警告浩嫌,局部加入或關(guān)閉
Clang提供了我們自己加入警告或者暫時(shí)關(guān)閉警告的方法檐迟。
//Generate a warning
#pragma message "Warning 1"
//Another way to generate a warning
#warning "Warning 2"
兩種強(qiáng)制警告的方法在視覺(jué)效果上是一樣的,但是警告的類(lèi)型略有不同码耐,一個(gè)是-W#pragma-messages
追迟,另一個(gè)是-W#warnings
。對(duì)于第二種寫(xiě)法骚腥,把warning換成error敦间,可以強(qiáng)制使編譯失敗。比如發(fā)布一些需要API Key之類(lèi)的類(lèi)庫(kù)束铭,可以使用這個(gè)方法來(lái)提示別的開(kāi)發(fā)者別忘了輸入必要的信息廓块。
//Generate an error to fail the build.
#error "Something wrong"
對(duì)于關(guān)閉警告,如果要全局關(guān)閉的話契沫,直接在Other C Flags里寫(xiě) -Wno-...
就行了带猴,比如-Wextra -Wno-sign-compare
就是一個(gè)常見(jiàn)的組合。如果想對(duì)某幾個(gè)文件開(kāi)啟或禁用警告懈万,在Build Phases
的Compile Source
相應(yīng)的文件中加入對(duì)應(yīng)的編譯標(biāo)識(shí)即可拴清。如果只是想在某幾行關(guān)閉某個(gè)警告的話靶病,可以通過(guò)臨時(shí)改變?cè)\斷編譯標(biāo)記來(lái)抑制指定類(lèi)型的警告,具體如下:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
int a;
#pragma clang diagnostic pop
如果a之后沒(méi)有被使用口予,也不會(huì)出現(xiàn)未使用變量的警告了娄周。對(duì)于想要抑制的警告類(lèi)型的標(biāo)識(shí)名,可以在build產(chǎn)生的警告后的build log
中看到沪停。
三煤辨、關(guān)于Clang diagnostics的思考
我應(yīng)該開(kāi)啟哪些警告提示
個(gè)人喜好(代碼潔癖)不同,會(huì)有不同的需求牙甫。我的建議是對(duì)于所有項(xiàng)目掷酗,特別是新開(kāi)的項(xiàng)目,首先開(kāi)啟
-Wall
和-Wextra
窟哺,然后在此基礎(chǔ)上構(gòu)建項(xiàng)目并且避免一切警告泻轰。如果在開(kāi)發(fā)過(guò)程中遇到了某些確實(shí)無(wú)法解決或者確信自己的做法是正確的話(其實(shí)這種情況,你的做法一般即使不是錯(cuò)誤的且轨,也會(huì)是不那么正確的)浮声,可以有選擇性地關(guān)閉某些警告。一般來(lái)說(shuō)旋奢,關(guān)閉的警告項(xiàng)目不應(yīng)該超過(guò)一只手能數(shù)出來(lái)的數(shù)字泳挥,否則一定哪兒出問(wèn)題了..
是否要讓警告等于錯(cuò)誤
一種很常見(jiàn)的做法和代碼潔癖是將警告標(biāo)識(shí)為錯(cuò)誤,從而中斷編譯過(guò)程至朗。這讓開(kāi)發(fā)者不得不去修復(fù)這些警告屉符,從而保持代碼干凈整潔。在Xcode中锹引,可以通過(guò)勾選相應(yīng)的Treat Warnings as Errors
來(lái)開(kāi)啟矗钟,或者加入-Werror
標(biāo)識(shí)。我個(gè)人來(lái)說(shuō)不喜歡使用這個(gè)設(shè)定嫌变,因?yàn)樗偸谴驍嚅_(kāi)發(fā)流程吨艇。很多時(shí)候并不可能把代碼全寫(xiě)完再編譯調(diào)試,相反地腾啥,我更喜歡寫(xiě)一點(diǎn)就編譯運(yùn)行一下看看結(jié)果东涡,這樣在中間debug編譯的時(shí)候會(huì)出現(xiàn)警告也不足為奇。另外倘待,如果做TDD開(kāi)發(fā)時(shí)疮跑,也可能會(huì)有大量正常的警告出現(xiàn),如果有警告就不讓編譯的話凸舵,開(kāi)發(fā)效率可能會(huì)打折扣祸挪。一個(gè)比較好的做法是只在Release Build時(shí)將警告視為錯(cuò)誤,因?yàn)閄code中是可以為Debug和Release分別指定標(biāo)識(shí)的贞间,所以這很容易做到贿条。
另外也可以只把某些警告當(dāng)作錯(cuò)誤,-Werror=...
即可增热,同樣地整以,也可以在-Werror
被激活時(shí)使用-Wno-error=...
來(lái)使某些警告不成為錯(cuò)誤。結(jié)合使用這些編譯標(biāo)識(shí)可以達(dá)到很好的控制峻仇。
ps:全面的 Clang 警告綜合列表公黑,可以在這里找到:F***ingClangWarnings.com
在GCC的手冊(cè)中有一個(gè)參考。雖然蘋(píng)果現(xiàn)在用的都是LLVM了摄咆,但是這部分內(nèi)容應(yīng)該是繼承了GCC的設(shè)定凡蚜。
不顯示pod的警告
添加到你的Podfile:
platform :ios, '8.0'
# ignore all warnings from all pods
inhibit_all_warnings!
# ignore warnings from a specific pod
pod 'Facebook-iOS-SDK', :inhibit_warnings => true
這樣依賴,所有通過(guò)cocoaPods安裝的第三方庫(kù)的警告就沒(méi)有了吭从。
也可以朝蜘,如下圖所示,單獨(dú)忽略某一個(gè)第三方的所有警告