本篇內(nèi)容主要講解“怎么通過靜態(tài)分析提高iOS代碼質(zhì)量”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“怎么通過靜態(tài)分析提高iOS代碼質(zhì)量”吧!
為平橋等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及平橋網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站設(shè)計制作、網(wǎng)站建設(shè)、平橋網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!
隨著項目的擴大,依靠人工codereview來保證項目的質(zhì)量,越來越不現(xiàn)實,這時就有必要借助于一種自動化的代碼審查工具:程序靜態(tài)分析。
程序靜態(tài)分析(Program Static Analysis)是指在不運行代碼的方式下,通過詞法分析、語法分析、控制流、數(shù)據(jù)流分析等技術(shù)對程序代碼進行掃描,驗證代碼是否滿足規(guī)范性、安全性、可靠性、可維護性等指標的一種代碼分析技術(shù)。(來自百度百科)
詞法分析,語法分析等工作是由編譯器進行的,所以對iOS項目為了完成靜態(tài)分析,我們需要借助于編譯器。對于OC語言的靜態(tài)分析可以完全通過 Clang,對于Swift的靜態(tài)分析除了Clange還需要借助于 SourceKit。
Swift語言對應(yīng)的靜態(tài)分析工具是SwiftLint,OC語言對應(yīng)的靜態(tài)分析工具有Infer和OCLitn。以下會是對各個靜態(tài)分析工具的安裝和使用做一個介紹。
對于Swift項目的靜態(tài)分析可以使用 SwiftLint。SwiftLint 是一個用于強制檢查 Swift 代碼風(fēng)格和規(guī)定的一個工具。它的實現(xiàn)是 Hook 了 Clang 和 SourceKit 從而能夠使用 AST 來表示源代碼文件的更多精確結(jié)果。Clange我們了解了,那SourceKit是干什么用的?
SourceKit包含在 Swift項目的主倉庫,它是一套工具集,支持Swift的大多數(shù)源代碼操作特性:源代碼解析、語法突出顯示、排版、自動完成、跨語言頭生成等工作。
安裝有兩種方式,任選其一: 方式一:通過Homebrew
$ brew install swiftlint
這種是全局安裝,各個應(yīng)用都可以使用。 方式二:通過CocoaPods
pod 'SwiftLint', :configurations => ['Debug']
這種方式相當(dāng)于把SwiftLint作為一個三方庫集成進了項目,因為它只是調(diào)試工具,所以我們應(yīng)該將其指定為僅Debug環(huán)境下生效。
我們需要在項目中的Build Phases
,添加一個Run Script Phase
。如果是通過homebrew安裝的,你的腳本應(yīng)該是這樣的。
if which swiftlint >/dev/null; then swiftlint else echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" fi
如果是通過cocoapods安裝的,你得腳本應(yīng)該是這樣的:
"${PODS_ROOT}/SwiftLint/swiftlint"
鍵入CMD + B
編譯項目,在編譯完后會運行我們剛才加入的腳本,之后我們就能看到項目中大片的警告信息。有時候build信息并不能填入項目代碼中,我們可以在編譯的log日志里查看。
SwiftLint規(guī)則太多了,如果我們不想執(zhí)行某一規(guī)則,或者想要濾掉對Pods庫的分析,我們可以對SwfitLint進行配置。
在項目根目錄新建一個.swiftlint.yml
文件,然后填入如下內(nèi)容:
disabled_rules: # rule identifiers to exclude from running - colon - trailing_whitespace - vertical_whitespace - function_body_length opt_in_rules: # some rules are only opt-in - empty_count # Find all the available rules by running: # swiftlint rules included: # paths to include during linting. `--path` is ignored if present. - Source excluded: # paths to ignore during linting. Takes precedence over `included`. - Carthage - Pods - Source/ExcludedFolder - Source/ExcludedFile.swift - Source/*/ExcludedFile.swift # Exclude files with a wildcard analyzer_rules: # Rules run by `swiftlint analyze` (experimental) - explicit_self # configurable rules can be customized from this configuration file # binary rules can set their severity level force_cast: warning # implicitly force_try: severity: warning # explicitly # rules that have both warning and error levels, can set just the warning level # implicitly line_length: 110 # they can set both implicitly with an array type_body_length: - 300 # warning - 400 # error # or they can set both explicitly file_length: warning: 500 error: 1200 # naming rules can set warnings/errors for min_length and max_length # additionally they can set excluded names type_name: min_length: 4 # only warning max_length: # warning and error warning: 40 error: 50 excluded: iPhone # excluded via string allowed_symbols: ["_"] # these are allowed in type names identifier_name: min_length: # only min_length error: 4 # only error excluded: # excluded via string array - id - URL - GlobalAPIKey reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown)
一條rules提示如下,其對應(yīng)的rules名就是function_body_length
。
! Function Body Length Violation: Function body should span 40 lines or less excluding comments and whitespace: currently spans 43 lines (function_body_length)
disabled_rules
下填入我們不想遵循的規(guī)則。
excluded
設(shè)置我們想跳過檢查的目錄,Carthage、Pod、SubModule這些一般可以過濾掉。
其他的一些像是文件長度(file_length),類型名長度(type_name),我們可以通過設(shè)置具體的數(shù)值來調(diào)節(jié)。
另外SwiftLint也支持自定義規(guī)則,我們可以根據(jù)自己的需求,定義自己的rule
。
如果我們想將此次分析生成一份報告,也是可以的(該命令是通過homebrew安裝的swiftlint):
# reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown) $ swiftlint lint --reporter html > swiftlint.html
xcodebuild是xcode內(nèi)置的編譯命令,我們可以用它來編譯打包我們的iOS項目,接下來介紹的Infer和OCLint都是基于xcodebuild的編譯產(chǎn)物進行分析的,所以有必要簡單介紹一下它。
一般編譯一個項目,我們需要指定項目名,configuration,scheme,sdk等信息以下是幾個簡單的命令及說明。
# 不帶pod的項目,target名為TargetName,在Debug下,指定模擬器sdk環(huán)境進行編譯 xcodebuild -target TargetName -configuration Debug -sdk iphonesimulator # 帶pod的項目,workspace名為TargetName.xcworkspace,在Release下,scheme為TargetName,指定真機環(huán)境進行編譯。不指定模擬器環(huán)境會驗證證書 xcodebuild -workspace WorkspaceName.xcworkspace -scheme SchemeName Release # 清楚項目的編譯產(chǎn)物 xcodebuild -workspace WorkspaceName.xcworkspace -scheme SchemeName Release clean
之后對xcodebuild命令的使用都需要將這些參數(shù)替換為自己項目的參數(shù)。
Infer是Facebook開發(fā)的針對C、OC、Java語言的靜態(tài)分析工具,它同時支持對iOS和Android應(yīng)用的分析。對于Facebook內(nèi)部的應(yīng)用像是 Messenger、Instagram 和其他一些應(yīng)用均是有它進行靜態(tài)分析的。它主要檢測隱含的問題,主要包括以下幾條:
資源泄露,內(nèi)存泄露
變量和參數(shù)的非空檢測
循環(huán)引用
過早的nil操作
暫不支持自定義規(guī)則。
$ brew install infer
運行infer
$ cd projectDir # 跳過對Pods的分析 $ infer run --skip-analysis-in-path Pods -- xcodebuild -workspace "Project.xcworkspace" -scheme "Scheme" -configuration Debug -sdk iphonesimulator
我們會得到一個infer-out
的文件夾,里面是各種代碼分析的文件,有txt,json等文件格式,當(dāng)這樣不方便查看,我們可以將其轉(zhuǎn)成html格式:
$ infer explore --html
點擊trace,我們會看到該問題代碼的上下文。
因為Infer默認是增量編譯,只會分析變動的代碼,如果我們想整體編譯的話,需要clean一下項目:
$ xcodebuild -workspace "Project.xcworkspace" -scheme "Scheme" -configuration Debug -sdk iphonesimulator clean
再次運行Infer去編譯。
$ infer run --skip-analysis-in-path Pods -- xcodebuild -workspace "Project.xcworkspace" -scheme "Scheme" -configuration Debug -sdk iphonesimulator
Infer的靜態(tài)分析主要分兩個階段:
1、捕獲階段
Infer 捕獲編譯命令,將文件翻譯成 Infer 內(nèi)部的中間語言。
這種翻譯和編譯類似,Infer 從編譯過程獲取信息,并進行翻譯。這就是我們調(diào)用 Infer 時帶上一個編譯命令的原因了,比如:
infer -- clang -c file.c
,
infer -- javac File.java
。結(jié)果就是文件照常編譯,同時被 Infer 翻譯成中間語言,留作第二階段處理。特別注意的就是,如果沒有文件被編譯,那么也沒有任何文件會被分析。
Infer 把中間文件存儲在結(jié)果文件夾中,一般來說,這個文件夾會在運行
infer
的目錄下創(chuàng)建,命名是
infer-out/
。
2、分析階段
在分析階段,Infer 分析
infer-out/
下的所有文件。分析時,會單獨分析每個方法和函數(shù)。
在分析一個函數(shù)的時候,如果發(fā)現(xiàn)錯誤,將會停止分析,但這不影響其他函數(shù)的繼續(xù)分析。
所以你在檢查問題的時候,修復(fù)輸出的錯誤之后,需要繼續(xù)運行 Infer 進行檢查,知道確認所有問題都已經(jīng)修復(fù)。
錯誤除了會顯示在標準輸出之外,還會輸出到文件
infer-out/bug.txt
中,我們過濾這些問題,僅顯示最有可能存在的。
在結(jié)果文件夾中(infer-out
),同時還有一個 csv 文件
report.csv
,這里包含了所有 Infer 產(chǎn)生的信息,包括:錯誤,警告和信息。
OCLint是基于 Clange Tooling編寫的庫,它支持擴展,檢測的范圍比Infer要大。不光是隱藏bug,一些代碼規(guī)范性的問題,例如命名和函數(shù)復(fù)雜度也均在檢測范圍之內(nèi)。
OCLint一般通過Homebrew安裝
$ brew tap oclint/formulae $ brew install oclint
通過Hombrew安裝的版本為0.13。
$ oclint --version LLVM (http://llvm.org/): LLVM version 5.0.0svn-r313528 Optimized build. Default target: x86_64-apple-darwin19.0.0 Host CPU: skylake OCLint (http://oclint.org/): OCLint version 0.13. Built Sep 18 2017 (08:58:40).
我分別用Xcode11在兩個項目上運行過OCLint,一個實例項目可以正常運行,另一個復(fù)雜的項目卻運行失敗,報如下錯誤:
1 error generated 1 error generated ... oclint: error: cannot open report output file ..../onlintReport.html
我并不清楚原因,如果你想試試0.13能否使用的話,直接跳到安裝xcpretty。如果你也遇到了這個問題,可以回來安裝oclint0.15版本。
我在 oclint issuse #547這里找到了這個問題和對應(yīng)的解決方案。
我們需要更新oclint至0.15版本。brew上的最新版本是0.13,github上的最新版本是0.15。我下載github上的release0.15版本,但是這個包并不是編譯過的,不清楚是不是官方自己搞錯了,只能手動編譯了。因為編譯要下載llvm和clange,這兩個包較大,所以我將編譯過后的包直接傳到了這里 CodeChecker。
如果不關(guān)心編譯過程,可以下載編譯好的包,跳到設(shè)置環(huán)境變量那一步。
編譯OCLint
1、安裝 CMake和 Ninja這兩個編譯工具
$ brew install cmake ninja
2、clone OCLint項目
$ git clone https://github.com/oclint/oclint
3、進入oclint-scripts目錄,執(zhí)行make命令
$ ./make
成功之后會出現(xiàn)build文件夾,里面有個oclint-release就是編譯成功的oclint工具。
設(shè)置oclint工具的環(huán)境變量
設(shè)置環(huán)境變量的目的是為了我們能夠快捷訪問。然后我們需要配置PATH環(huán)境變量,注意OCLint_PATH的路徑為你存放oclint-release的路徑。將其添加到.zshrc
,或者.bash_profile
文件末尾:
OCLint_PATH=/Users/zhangferry/oclint/build/oclint-release export PATH=$OCLint_PATH/bin:$PATH
執(zhí)行source .zshrc
,刷新環(huán)境變量,然后驗證oclint是否安裝成功:
$ oclint --version OCLint (http://oclint.org/): OCLint version 0.15. Built May 19 2020 (11:48:49).
出現(xiàn)這個介紹就說明我們已經(jīng)完成了安裝。
xcpretty是一個格式化xcodebuild輸出內(nèi)容的腳本工具,oclint的解析依賴于它的輸出。它的安裝方式為:
$ gem install xcpretty
在使用OCLint之前還需要一些準備工作,需要將編譯項COMPILER_INDEX_STORE_ENABLE
設(shè)置為NO。
將 Project 和 Targets 中 Building Settings 下的
COMPILER_INDEX_STORE_ENABLE
設(shè)置為
NO
在 podfile 中 target ‘target’ do 前面添加下面的腳本,將各個pod的編譯配置也改為此選項
post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['COMPILER_INDEX_STORE_ENABLE'] = "NO" end end end
1、進入項目根目錄,運行如下腳本:
$ xcodebuild -workspace ProjectName.xcworkspace -scheme ProjectScheme -configuration Debug -sdk iphonesimulator | xcpretty -r json-compilation-database -o compile_commands.json
會將xcodebuild編譯過程中的一些信息記錄成一個文件compile_commands.json
,如果我們在項目根目錄看到了該文件,且里面是有內(nèi)容的,證明我們完成了第一步。
2、我們將這個json文件轉(zhuǎn)成方便查看的html,過濾掉對Pods文件的分析,為了防止行數(shù)上限,我們加上行數(shù)的限制:
$ oclint-json-compilation-database -e Pods -- -report-type html -o oclintReport.html -rc LONG_LINE=9999 -max-priority-1=9999 -max-priority-2=9999 -max-priority-3=9999
最終會產(chǎn)生一個oclintReport.html
文件。
OCLint支持自定義規(guī)則,因為其本身規(guī)則已經(jīng)很豐富了,自定義規(guī)則的需求應(yīng)該很小,也就沒有嘗試。
封裝腳本
OCLint跟Infer一樣都是通過運行幾個腳本語言進行執(zhí)行的,我們可以將這幾個命令封裝成一個腳本文件,以O(shè)CLint為例,Infer也類似:
#!/bin/bash # mark sure you had install the oclint and xcpretty # You need to replace these values with your own project configuration workspace_name="WorkSpaceName.xcworkspace" scheme_name="SchemeName" # remove history rm compile_commands.json rm oclint_result.xml # clean project # -sdk iphonesimulator means run simulator xcodebuild -workspace $workspace_name -scheme $scheme_name -configuration Debug -sdk iphonesimulator clean || (echo "command failed"; exit 1); # export compile_commands.json xcodebuild -workspace $workspace_name -scheme $scheme_name -configuration Debug -sdk iphonesimulator \ | xcpretty -r json-compilation-database -o compile_commands.json \ || (echo "command failed"; exit 1); # export report html # you can run `oclint -help` to see all USAGE oclint-json-compilation-database -e Pods -- -report-type html -o oclintReport.html \ -disable-rule ShortVariableName \ -rc LONG_LINE=1000 \ || (echo "command failed"; exit 1); open -a "/Applications/Safari.app" oclintReport.html
oclint-json-compilation-database
命令的幾個參數(shù)說明:
-e
需要忽略分析的文件,這些文件的警告不會出現(xiàn)在報告中
-rc
需要覆蓋的規(guī)則的閥值,這里可以自定義項目的閥值,
默認閥值
-enable-rule
支持的規(guī)則,默認是oclint提供的都支持,可以組合-disable-rule來過濾掉一些規(guī)則
規(guī)則列表
-disable-rule
需要忽略的規(guī)則,根據(jù)項目需求設(shè)置
因為OCLint提供了xcode格式的輸出樣式,所以我們可以將它作為一個腳本放在Xcode中。
1、在項目的 TARGETS 下面,點擊下方的 “+” ,選擇 cross-platform 下面的 Aggregate。輸入名字,這里命名為 OCLint
2、選中該Target,進入Build Phases,添加Run Script,寫入下面腳本:
# Type a script or drag a script file from your workspace to insert its path. # 內(nèi)置變量 cd ${SRCROOT} xcodebuild clean xcodebuild | xcpretty -r json-compilation-database oclint-json-compilation-database -e Pods -- -report-type xcode
可以看出該腳本跟上面的腳本一樣,只不過 將oclint-json-compilation-database
命令的-report-type
由html
改為了xcode
。而OCLint作為一個target本身就運行在特定的環(huán)境下,所以xcodebuild可以省去配置參數(shù)。
3、通過CMD + B
我們編譯一下項目,執(zhí)行腳本任務(wù),會得到能夠定位到代碼的warning信息:
到此,相信大家對“怎么通過靜態(tài)分析提高iOS代碼質(zhì)量”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
新聞標題:怎么通過靜態(tài)分析提高iOS代碼質(zhì)量
文章路徑:http://jinyejixie.com/article34/psidse.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、靜態(tài)網(wǎng)站、Google、網(wǎng)站排名、電子商務(wù)、動態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)