簡(jiǎn)介
SwiftLint 是 realm 公司開(kāi)發(fā)的一個(gè)插件,用于強(qiáng)制檢查 Swift 代碼風(fēng)格和規(guī)則的一個(gè)工具。
SwiftLint 的工作原理是檢查 Swift 代碼編譯過(guò)程中的 AST 和 SourceKit 環(huán)節(jié),從而可以擺脫不同版本 Swift 語(yǔ)法變化的影響。AST 是編譯前端形成的抽象語(yǔ)法樹(shù)(Abstract Symbolic Tree), SourceKit 過(guò)程用來(lái)對(duì) AST 進(jìn)行代碼優(yōu)化,減少內(nèi)存開(kāi)銷(xiāo),提高執(zhí)行效率。
安裝
1. 使用 Homebrew:
brew install swiftlint
2. 使用 CocoaPods:
將如下代碼添加到你的 Podfile 即可:
pod 'SwiftLint'
3. 使用安裝包:
通過(guò)從 最新的 GitHub 發(fā)布地址 下載 SwiftLint.pkg 然后執(zhí)行的方式安裝 SwiftLint。
用法
1. Xcode:
在 Xcode-Project-Build Phases-+(New Run Script Phase) 中添加一個(gè)新的 Script Phase 并且包含如下代碼即可:
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi

2. 命令行:
在有需要執(zhí)行代碼分析的 Swift 源碼文件的目錄下執(zhí)行 swiftlint 命令,會(huì)對(duì)目錄遞歸查找。
$ swiftlint help
autocorrect Automatically correct warnings and errors
help Display general or command-specific help
lint Print lint warnings and errors for the Swift files in the current directory (default command)
rules Display the list of rules and their identifiers
version Display the current version of SwiftLint
規(guī)則
1. 終端執(zhí)行命令: swiftlint rules 或者 官方文檔: rule-directory
opt-in: 為 yes 時(shí),規(guī)則默認(rèn)不生效,需要添加進(jìn)配置的 opt_in_rules 時(shí)生效
correctable: 為 yes 時(shí),執(zhí)行 swiftlint autocorrect 命令,會(huì)自動(dòng)修改代碼格式為正確的格式
enabled in your config: 為 yes 時(shí),規(guī)則默認(rèn)生效,不需要額外配置
kind: 規(guī)則類(lèi)型,僅用于規(guī)則的分類(lèi)
analyzer: 為 yes 時(shí),可在 Xcode 的 Analyze 生效
configuration: 支持配置的屬性默認(rèn)值。例: warning 代表不符合代碼規(guī)則時(shí),編譯器會(huì)警告。可在配置文件中改成 error,編譯器會(huì)報(bào)錯(cuò)
rules 列表詳見(jiàn)文章底部 附錄 1. swiftlint rules
2. 規(guī)則開(kāi)啟與關(guān)閉
可以通過(guò)在一個(gè)源文件中定義一個(gè)如下格式的注釋來(lái)關(guān)閉某個(gè)規(guī)則:
// swiftlint:disable <rule>
在該文件結(jié)束之前或者在定義如下格式的匹配注釋之前,這條規(guī)則都會(huì)被禁用:
// swiftlint:enable <rule>
也可以通過(guò)添加 :previous, :this 或者 :next 來(lái)使關(guān)閉或者打開(kāi)某條規(guī)則的命令分別應(yīng)用于前一行,當(dāng)前或者后一行代碼。
// swiftlint:disable:next force_cast
let noWarning = NSNumber() as! Int
let hasWarning = NSNumber() as! Int
let noWarning2 = NSNumber() as! Int // swiftlint:disable:this force_cast
let noWarning3 = NSNumber() as! Int
// swiftlint:disable:previous force_cast
配置
在需要執(zhí)行 SwiftLint 的目錄下添加一個(gè) .swiftlint.yml 文件的方式來(lái)配置 SwiftLint??梢员慌渲玫膮?shù)有:
- disabled_rules: 關(guān)閉某些默認(rèn)開(kāi)啟的規(guī)則。
- opt_in_rules: 一些規(guī)則是可選的,添加到這里才會(huì)生效。
- only_rules: 不可以和 disabled_rules 或者 opt_in_rules 并列。類(lèi)似一個(gè)白名單,只有在這個(gè)列表中的規(guī)則才是開(kāi)啟的。
disabled_rules: # 執(zhí)行時(shí)排除掉的規(guī)則
- colon
opt_in_rules: # 一些規(guī)則僅僅是可選的
- empty_count
included: # 執(zhí)行 linting 時(shí)包含的路徑。
- Source
excluded: # 執(zhí)行 linting 時(shí)忽略的路徑。 優(yōu)先級(jí)比 `included` 更高。
- Carthage
force_cast: warning # 隱式
force_try:
severity: warning # 顯式
type_body_length: # 可以通過(guò)一個(gè)數(shù)組同時(shí)進(jìn)行隱式設(shè)置
- 300 # warning
- 400 # error
file_length: # 或者也可以同時(shí)進(jìn)行顯式設(shè)置
warning: 500
error: 1200
reporter: "xcode" # 報(bào)告類(lèi)型 (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging)
自定義規(guī)則
在配置文件 .swiftlint.yml 里定義基于正則表達(dá)式的自定義規(guī)則:
custom_rules:
pirates_beat_ninjas: # 規(guī)則標(biāo)識(shí)符
name: "Pirates Beat Ninjas" # 規(guī)則名稱(chēng),可選
regex: "([nN]inja)" # 匹配的模式
match_kinds: # 需要匹配的語(yǔ)法類(lèi)型,可選
- comment
- identifier
message: "Pirates are better than ninjas." # 提示信息,可選
severity: error # 提示的級(jí)別,可選
no_hiding_in_strings:
regex: "([nN]inja)"
match_kinds: string
輸出大概可能是這個(gè)樣子的:

通過(guò)提供一個(gè)或者多個(gè) match_kinds 的方式來(lái)對(duì)匹配進(jìn)行篩選,它會(huì)將含有不包括在列表中的語(yǔ)法類(lèi)型的匹配排除掉。這里有全部可用的語(yǔ)法類(lèi)型:
argument attribute.builtin attribute.id buildconfig.id buildconfig.keyword comment comment.mark comment.url doccomment doccomment.field identifier keyword number objectliteral parameter placeholder string string_interpolation_anchor typeidentifier
嵌套配置
SwiftLint 支持通過(guò)嵌套配置文件的方式來(lái)對(duì)代碼分析過(guò)程進(jìn)行更加細(xì)致的控制。
- 在你需要的目錄引入 .swiftlint.yml。
- 在目錄結(jié)構(gòu)必要的地方引入額外的 .swiftlint.yml 文件。
- 每個(gè)文件被檢查時(shí)會(huì)使用在文件所在目錄下的或者父目錄的更深層目錄下的配置文件。否則根配置文件將會(huì)生效。
- excluded 和 included 在嵌套結(jié)構(gòu)中會(huì)被忽略。
自動(dòng)更正
SwiftLint 可以自動(dòng)修正某些錯(cuò)誤,磁盤(pán)上的文件會(huì)被一個(gè)修正后的版本覆蓋。
請(qǐng)確保在對(duì)文件執(zhí)行 swiftlint autocorrect 之前有對(duì)它們做過(guò)備份,否則的話(huà)有可能導(dǎo)致重要數(shù)據(jù)的丟失。
因?yàn)樵趫?zhí)行自動(dòng)更正修改某個(gè)文件后很有可能導(dǎo)致之前生成的代碼檢查信息無(wú)效或者不正確,所以當(dāng)在執(zhí)行代碼更正時(shí)標(biāo)準(zhǔn)的檢查是無(wú)法使用的。
SwiftLint rules 原理
SwiftLint rules 的源碼在 Source/SwiftLintFramework/Rules 目錄下,以 OverriddenSuperCallRule(方法需要調(diào)用 super method) 為例解讀源碼,路徑為:/Source/SwiftLintFramework/Rules/Lint/OverriddenSuperCallRule.swift。
| overridden_super_call | yes | no | no | lint | no | warning, excluded: [], included: [“*"] |
主要看 validate(file:kind:dictionary:) 方法,在方法中使用了 configuration、SourceKittenDictionary。
configuration: OverriddenSuperCallConfiguration
public struct OverriddenSuperCallConfiguration: RuleConfiguration, Equatable {
private let defaultIncluded = [
"addChildViewController(_:)",
"didReceiveMemoryWarning()",
"removeFromParentViewController()",
"viewDidAppear(_:)",
"viewDidDisappear(_:)",
"viewDidLoad()",
"viewWillAppear(_:)",
"viewWillDisappear(_:)",
...
]
var severityConfiguration = SeverityConfiguration(.warning)
var excluded: [String] = []
var included: [String] = ["*"]
public private(set) var resolvedMethodNames: [String]
init() {
resolvedMethodNames = defaultIncluded
}
public var consoleDescription: String {
return severityConfiguration.consoleDescription +
", excluded: \(excluded)" +
", included: \(included)"
}
public mutating func apply(configuration: Any) throws {
guard let configuration = configuration as? [String: Any] else {
throw ConfigurationError.unknownConfiguration
}
if let severityString = configuration["severity"] as? String {
try severityConfiguration.apply(configuration: severityString)
}
if let excluded = [String].array(of: configuration["excluded"]) {
self.excluded = excluded
}
if let included = [String].array(of: configuration["included"]) {
self.included = included
}
resolvedMethodNames = calculateResolvedMethodNames()
}
public var severity: ViolationSeverity {
return severityConfiguration.severity
}
private func calculateResolvedMethodNames() -> [String] {
var names: [String] = []
if included.contains("*") && !excluded.contains("*") {
names += defaultIncluded
}
names += included.filter({ $0 != "*" })
names = names.filter { !excluded.contains($0) }
return names
}
}
- defaultIncluded: 默認(rèn)的配置,里面有一些方法名。
- severityConfiguration: 規(guī)則沖突提示級(jí)別
- excluded: 需要排除的方法
- included:需要包含的方法
- func apply(configuration: Any): 應(yīng)用自定義的配置
- calculateResolvedMethodNames(): 綜合配置
SourceKittenDictionary 使用 [String: SourceKitRepresentable] 初始化。
[String: SourceKitRepresentable] 是 sourcekitten structure --file SourcekittenDemoViewController.swift 命令生成的 json 對(duì)象。詳看: sourcekitten_structure.json
SourceKittenDictionary
public struct SourceKittenDictionary {
init(_ value: [String: SourceKitRepresentable]) {…}
…
以 SourcekittenDemoViewController.swift 為例:
class SourcekittenDemoViewController: UIViewController {
private var testVar: String?
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.lightGray
testVar = "i am testVar"
}
}
sourcekitten_structure.json
{
"key.diagnostic_stage" : "source.diagnostic.stage.swift.parse",
"key.length" : 414,
"key.offset" : 0,
"key.substructure" : [
{
"key.accessibility" : "source.lang.swift.accessibility.internal",
"key.bodylength" : 189,
"key.bodyoffset" : 223,
"key.elements" : [
{
"key.kind" : "source.lang.swift.structure.elem.typeref",
"key.length" : 16,
"key.offset" : 205
}
],
"key.inheritedtypes" : [
{
"key.name" : "UIViewController"
}
],
"key.kind" : "source.lang.swift.decl.class",
"key.length" : 246,
"key.name" : "SourcekittenDemoViewController",
"key.namelength" : 30,
"key.nameoffset" : 173,
"key.offset" : 167,
"key.substructure" : [
{
"key.accessibility" : "source.lang.swift.accessibility.private",
"key.attributes" : [
{
"key.attribute" : "source.decl.attribute.private",
"key.length" : 7,
"key.offset" : 228
}
],
"key.kind" : "source.lang.swift.decl.var.instance",
"key.length" : 20,
"key.name" : "testVar",
"key.namelength" : 7,
"key.nameoffset" : 240,
"key.offset" : 236,
"key.setter_accessibility" : "source.lang.swift.accessibility.private",
"key.typename" : "String?"
},
{
"key.accessibility" : "source.lang.swift.accessibility.internal",
"key.attributes" : [
{
"key.attribute" : "source.decl.attribute.override",
"key.length" : 8,
"key.offset" : 261
}
],
"key.bodylength" : 120,
"key.bodyoffset" : 290,
"key.kind" : "source.lang.swift.decl.function.method.instance",
"key.length" : 141,
"key.name" : "viewDidLoad()",
"key.namelength" : 13,
"key.nameoffset" : 275,
"key.offset" : 270,
"key.substructure" : [
{
"key.bodylength" : 0,
"key.bodyoffset" : 317,
"key.kind" : "source.lang.swift.expr.call",
"key.length" : 19,
"key.name" : "super.viewDidLoad",
"key.namelength" : 17,
"key.nameoffset" : 299,
"key.offset" : 299
}
]
}
]
}
]
}
validate(file:kind:dictionary:)
func validate(file: SwiftLintFile, kind: SwiftDeclarationKind,
dictionary: SourceKittenDictionary) -> [StyleViolation] {
guard let offset = dictionary.bodyOffset,
let name = dictionary.name,
kind == .functionMethodInstance,
configuration.resolvedMethodNames.contains(name),
dictionary.enclosedSwiftAttributes.contains(.override)
else { return [] }
let callsToSuper = dictionary.extractCallsToSuper(methodName: name)
if callsToSuper.isEmpty {
…
"Method '\(name)' should call to super function"
} else if callsToSuper.count > 1 {
...
"Method '\(name)' should call to super only once"
}
return []
}
public struct SourceKittenDictionary {
…
internal func extractCallsToSuper(methodName: String) -> [String] {
guard let methodNameWithoutArguments = methodName.split(
separator: "(").first else { return [] }
let superCall = “super.\(methodNameWithoutArguments)"
return substructure.flatMap { elems -> [String] in
guard let type = elems.expressionKind,
let name = elems.name,
type == .call && superCall == name else {
return elems.extractCallsToSuper(
methodName: methodName)}
return [name]}}
}
validate(file:kind:dictionary:) 通過(guò)判斷:
方法 == 含有 .override 屬性的實(shí)例方法 &&
methodName 在配置列表中 &&
Substructure 中表達(dá)式類(lèi)型是 .call &&
Substructure 中方法調(diào)用名稱(chēng) == super.{methodName}
滿(mǎn)足上述條件的方法內(nèi)若沒(méi)有調(diào)用對(duì)應(yīng)的 super 方法,或者
調(diào)用了多次對(duì)應(yīng)的 super 方法,就會(huì)提示規(guī)則沖突。
問(wèn):sourcekitten 是什么?
答:SourceKitten 是基于 Apple 的 SourceKit 封裝的命令行工具,SourceKitten 鏈接并與 sourcekitd.framework 通信以解析 Swift AST,最終提取 Swift 或 ObjC 文件的類(lèi)結(jié)構(gòu)和方法等。
sourcekitten 支持的命令如下:
SUBCOMMANDS:
complete Generate code completion options
doc Print Swift or Objective-C docs as JSON
format Format Swift file
index Index Swift file and print as JSON
module-info Obtain Swift module information and print as json
request Run a raw SourceKit request
structure Print Swift structure information as JSON
syntax Print Swift syntax information as JSON
version Display the current version of SourceKitten
問(wèn):SourceKit 是什么?
答:SourceKit 是一套工具集,使得大多數(shù) Swift 源代碼層面的操作特性得以支持,例如源代碼解析、語(yǔ)法高亮、排版(typesetting)、自動(dòng)補(bǔ)全、跨語(yǔ)言頭文件生成,等等
問(wèn):Swift AST 是什么?
答:AST(Abstract Syntax Tree 抽象語(yǔ)法樹(shù)) 是源代碼的抽象語(yǔ)法結(jié)構(gòu)的樹(shù)狀表示,樹(shù)上的每個(gè)節(jié)點(diǎn)都表示源代碼中的一種結(jié)構(gòu),是 Swift 文件編譯過(guò)程中的產(chǎn)物。
Swift 文件編譯過(guò)程:


Swiftc 生成 AST:
Swiftc 是 swift 語(yǔ)言的編譯工具,它可以直接把 .swift 文件編譯生成可執(zhí)行文件,也可以產(chǎn)生編譯過(guò)程中某個(gè)中間文件。Swiftc 支持命令如下:
MODES:
-dump-ast Parse and type-check input file(s) and dump AST(s)
-dump-parse Parse input file(s) and dump AST(s)
-emit-assembly Emit assembly file(s) (-S)
-emit-executable Emit a linked executable
-emit-ir Emit LLVM IR file(s)
-emit-sibgen Emit serialized AST + raw SIL file(s)
-emit-sib Emit serialized AST + canonical SIL file(s)
-emit-silgen Emit raw SIL file(s)
-emit-sil Emit canonical SIL file(s)
-parse Parse input file(s)
-print-ast Parse and type-check input file(s) and pretty print AST(s)
-typecheck Parse and type-check input file(s)
...
swiftc -dump-parse SourcekittenDemoViewController.swift
(source_file "SourcekittenDemoViewController.swift"
(import_decl range=[SourcekittenDemoViewController.swift:9:1 - line:9:8] 'UIKit')
(class_decl range=[SourcekittenDemoViewController.swift:11:1 - line:18:1] "SourcekittenDemoViewController" inherits: <null>
(pattern_binding_decl range=[SourcekittenDemoViewController.swift:12:13 - line:12:32]
(pattern_typed
(pattern_named 'testVar')
(type_optional
(type_ident
(component id='String' bind=none)))))
(var_decl range=[SourcekittenDemoViewController.swift:12:17 - line:12:17] "testVar" type='<null type>' readImpl=stored writeImpl=stored readWriteImpl=stored)
(func_decl range=[SourcekittenDemoViewController.swift:13:14 - line:17:5] "viewDidLoad()"
(parameter "self")
(parameter_list range=[SourcekittenDemoViewController.swift:13:30 - line:13:31])
(brace_stmt range=[SourcekittenDemoViewController.swift:13:33 - line:17:5]
(call_expr type='<null>' arg_labels=
(unresolved_dot_expr type='<null>' field 'viewDidLoad' function_ref=unapplied
(super_ref_expr type='<null>'))
(tuple_expr type='()' location=SourcekittenDemoViewController.swift:14:26 range=[SourcekittenDemoViewController.swift:14:26 - line:14:27]))
(sequence_expr type='<null>'
(unresolved_dot_expr type='<null>' field 'backgroundColor' function_ref=unapplied
(unresolved_dot_expr type='<null>' field 'view' function_ref=unapplied
(declref_expr type='<null>' decl=SourcekittenDemoViewController.(file).SourcekittenDemoViewController.viewDidLoad().self@SourcekittenDemoViewController.swift:13:19 function_ref=unapplied)))
(assign_expr type='<null>'
(**NULL EXPRESSION**)
(**NULL EXPRESSION**))
(unresolved_dot_expr type='<null>' field 'lightGray' function_ref=unapplied
(unresolved_decl_ref_expr type='<null>' name=UIColor function_ref=unapplied)))
(sequence_expr type='<null>'
(unresolved_decl_ref_expr type='<null>' name=testVar function_ref=unapplied)
(assign_expr type='<null>'
(**NULL EXPRESSION**)
(**NULL EXPRESSION**))
(string_literal_expr type='<null>' encoding=utf8 value="i am testVar" builtin_initializer=**NULL** initializer=**NULL**))))))
通過(guò)生成的 AST 信息可以看到 import_decl、class_decl、var_decl、func_decl、brace_stmt、call_expr 等及所在的行列數(shù)。sourcekit 可以通過(guò)這些信息實(shí)現(xiàn)語(yǔ)法高亮、排版、自動(dòng)補(bǔ)全、跨語(yǔ)言頭文件生成,等等
提醒 執(zhí)行 swiftc -print-ast SourcekittenDemoViewController.swift 命令時(shí),終端會(huì)報(bào)錯(cuò) SourcekittenDemoViewController.swift:9:8: error: no such module 'UIKit' .
為解決此報(bào)錯(cuò),需要指定 -sdk 和 -target 參數(shù),如下:
swiftc -print-ast SourcekittenDemoViewController.swift -sdk /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.5.sdk -target arm64-apple-ios15.5
"15.5" 需要根據(jù)本地支持的版本做修改。
SwiftLint 規(guī)則建議
Swiftlint 規(guī)則沒(méi)有完全符合每個(gè)工程期望的統(tǒng)一規(guī)則?;陧?xiàng)目應(yīng)用上面,我得出一些經(jīng)驗(yàn)教訓(xùn),在此給出一點(diǎn)建議:
- 成熟的項(xiàng)目規(guī)則宜松不宜緊。規(guī)則過(guò)多或過(guò)嚴(yán)會(huì)直接導(dǎo)致產(chǎn)生較多警告,改動(dòng)太耗時(shí)間,產(chǎn)生大量提交。萬(wàn)一修改出了錯(cuò)誤,查起來(lái)也會(huì)非常麻煩。
-
可糾正代碼 bug 的規(guī)則,建議提示級(jí)別為 error,而非 warning。如此可及時(shí)提醒修正錯(cuò)誤。
例如: OverriddenSuperCallRule 規(guī)則可用于避免遺漏調(diào)用 super 方法,從而避免工程中對(duì)此方法的 hook 不生效。
例如: DiscardedNotificationCenterObserverRule 規(guī)則可用于避免因?yàn)槲闯钟?observer,不能釋放內(nèi)存,從而導(dǎo)致內(nèi)存泄露的 bug。 - 推薦 swift 寫(xiě)法的規(guī)則建議使用。
例如:使用 CGPoint(x:y:) 代替 CGPointMake(,)
基于上面三條建議,制定的規(guī)則示例如下:
only_rules:
- block_based_kvo # Swift 3.2 之后使用新的 KVO API
- compiler_protocol_init # 不應(yīng)該直接調(diào)用字面量轉(zhuǎn)換的初始化方法
- control_statement # if while 等判斷條件不要用括號(hào)括起來(lái)
- custom_rules # 一些自定義規(guī)則
- discarded_notification_center_observer # 當(dāng)使用 block 注冊(cè)通知中心 observer 的時(shí)候,應(yīng)該存儲(chǔ)函數(shù)返回的 observer, 以便之后的刪除
- discouraged_optional_boolean # 不建議使用可選布爾值
- duplicate_imports # 重復(fù)導(dǎo)入
- duplicate_enum_cases # 枚舉不能設(shè)置兩個(gè)或者以上相同的名字
- empty_count
- empty_string # 優(yōu)先使用 isEmpty 判斷,而不是將字符串與空字符串文字進(jìn)行比較
- empty_parameters # 閉包參數(shù)為空時(shí),建議使用 `() -> ` 代替 `Void ->
- explicit_init # 避免直接調(diào)用 init 方法
- fallthrough # switch 語(yǔ)句中不建議使用 fallthrough
- fatal_error_message # fatalError 必須擁有一個(gè) message
- file_name_no_space # 文件名不應(yīng)包含任何空格
- force_cast # 不建議直接強(qiáng)解類(lèi)型
- force_try # 避免 `try!`
- force_unwrapping # 避免強(qiáng)制解包
- identical_operands # 比較兩個(gè)相同的操作數(shù)可能是一個(gè)錯(cuò)誤
- legacy_cggeometry_functions # 避免使用 C 風(fēng)格的 CG 遺留函數(shù),使用 struct extension
- legacy_constructor # 使用 swift 提供的 struct 構(gòu)造函數(shù), 避免使用遺留的構(gòu)造函數(shù)比如 CGPointMake(10, 10)
- legacy_nsgeometry_functions # 避免使用 C 風(fēng)格的 NS 遺留函數(shù),使用 struct extension
- literal_expression_end_indentation # 數(shù)組和字典文字的結(jié)尾應(yīng)與開(kāi)始它的行具有相同的縮進(jìn)
- lower_acl_than_parent # 確保定義的訪問(wèn)控制級(jí)別低于其父級(jí)
- mark # 正確使用 mark 的格式 `// MARK: - message`
- multiline_parameters # 函數(shù)和方法參數(shù)應(yīng)該在同一行上,或者每行一個(gè)
- no_extension_access_modifier # 在 extension 擴(kuò)展前面,不建議使用 (fileprivate,public) 等修飾符
- redundant_objc_attribute # Objective-C 屬性(@objc)在聲明中是多余的
- redundant_optional_initialization # 不需要寫(xiě)默認(rèn)值為 nil
- redundant_string_enum_value # 字符串類(lèi)型枚舉,會(huì)有默認(rèn) string 值,與名字相同,不要再次設(shè)置
- redundant_void_return # 在不必要的時(shí)候, 不需要寫(xiě) ->() and -> Void
- return_arrow_whitespace # 函數(shù)定義返回的 -> 前后有空格, 不換行
- switch_case_alignment # Case 語(yǔ)句應(yīng)與其封閉的 switch 語(yǔ)句垂直對(duì)齊,如果沒(méi)有其他配置,則縮進(jìn)
- trailing_semicolon # 行末尾不加分號(hào)
- type_name # 類(lèi)型名字限制規(guī)則(類(lèi)型名稱(chēng)應(yīng)僅包含字母數(shù)字字符,以大寫(xiě)字符開(kāi)頭,長(zhǎng)度在 3 到 40 個(gè)字符之間)
- unneeded_break_in_switch # 在 switch-case 語(yǔ)句中, 有方法調(diào)用或操作時(shí),避免使用 break 語(yǔ)句
- unowned_variable_capture # 最好將引用捕獲為弱引用以避免潛在的崩潰
- void_return # 使用 `-> Void` 代替 `-> ()
- weak_delegate # delegate 應(yīng)該被設(shè)置為 weak
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Tests
- Example
- Resources
force_cast:
severity: warning
force_try:
severity: warning
no_extension_access_modifier:
severity: warning
empty_count:
severity: warning
type_name:
min_length: 1
max_length: 60
overridden_super_call:
severity: error
prohibited_super_call:
severity: error
discarded_notification_center_observer:
severity: error
weak_delegate:
severity: error
unowned_variable_capture:
severity: error
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown)
custom_rules:
ab_test_recovery:
name: "AB Test Recovery"
regex: '^ *//+[ \S]* ABTestHelper\.+'
match_kinds:
- comment
- doccomment
message: "AB Test Recovery. 調(diào)試期間注釋掉的 ab test,上線(xiàn)前記得恢復(fù)"
severity: warning
url_Check:
name: "URL Check"
regex: '(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]+[()()]'
match_kinds: string
message: "URL 中發(fā)現(xiàn)有 '(' 或 ')' 或 '(' 或 ')' ,請(qǐng)注意確認(rèn)正確性"
severity: warning
附錄
1. swiftlint rules
| identifier | opt-in | correctable | enabled in your config | kind | analyzer | configuration | comment |
|---|---|---|---|---|---|---|---|
| anyobject_protocol | yes | yes | no | lint | no | warning | 對(duì)于純類(lèi)協(xié)議,建議AnyObject 不推薦 class |
| array_init | yes | no | no | lint | no | warning | 推薦使用 Array(seq) 不推薦語(yǔ)法: seq.map { $0 } 將序列轉(zhuǎn)換為Array |
| attributes | yes | no | no | style | no | warning, always_on_same_line: ["@IBAction", "@NSManaged"], alwa... | 屬性應(yīng)該在函數(shù)和類(lèi)型中自己的行上,與變量和 imports 在同一行上 |
| balanced_xctest_lifecycle | yes | no | no | lint | no | warning | - |
| block_based_kvo | no | no | yes | idiomatic | no | warning | 屬性和下標(biāo)中的Getter和setter應(yīng)該保持一致的順序 |
| capture_variable | yes | no | no | lint | yes | warning | - |
| class_delegate_protocol | no | no | yes | lint | no | warning | delegate protocol 應(yīng)該被設(shè)定為 class-only,才能被弱引用 |
| closing_brace | no | yes | yes | style | no | warning | 小括號(hào)內(nèi)包含函數(shù)(大括號(hào))的時(shí)候,之間沒(méi)有空格 |
| closure_body_length | yes | no | no | metrics | no | warning: 20, error: 100 | 封閉體不應(yīng)跨越太多行 |
| closure_end_indentation | yes | yes | no | style | no | warning | 閉包前后縮進(jìn)應(yīng)相同 |
| closure_parameter_position | no | no | yes | style | no | warning | 閉包參數(shù)位置, 閉包參數(shù)應(yīng)該 { 左邊在同一行 |
| closure_spacing | yes | yes | no | style | no | warning | 閉包表達(dá)式在每個(gè)大括號(hào) { } 內(nèi)前后應(yīng)有一個(gè)空格 |
| collection_alignment | yes | no | no | style | no | warning, align_colons: false | 集合文字中的所有元素應(yīng)垂直對(duì)齊 |
| colon | no | yes | yes | style | no | warning, flexible_right_spacing: false, apply_to_dictionaries: ... | 冒號(hào)左邊沒(méi)有空格, 右邊有且只有一個(gè)空格 |
| comma | no | yes | yes | style | no | warning | 逗號(hào)左邊沒(méi)有空格, 右邊有空格 |
| comment_spacing | no | yes | yes | lint | no | warning | - |
| compiler_protocol_init | no | no | yes | lint | no | warning | 不應(yīng)該直接調(diào)用字面量轉(zhuǎn)換的初始化方法,諸如編譯器協(xié)議中聲明的初始化程序ExpressibleByArrayLiteral不應(yīng)直接調(diào)用 |
| computed_accessors_order | no | no | yes | style | no | warning, order: get_set | - |
| conditional_returns_on_newline | yes | no | no | style | no | warning, if_only: false | 條件語(yǔ)句與結(jié)果不建議寫(xiě)在一行 ,例如:guard true else { return } ;if true { return "YES" } else { return "NO" } 會(huì)有 warning提示 |
| contains_over_first_not_nil | yes | no | no | performance | no | warning | 推薦使用 contains,避免使用 first(where:) != nil 與 firstIndex(where:) != nil |
| control_statement | no | yes | yes | style | no | warning | if while 等判斷條件不要用括號(hào) 括起來(lái),另外注意條件出的空格 |
| convenience_type | yes | no | no | idiomatic | no | warning | 用于檢測(cè)靜態(tài)成員的類(lèi)型應(yīng)實(shí)現(xiàn)為無(wú)大小寫(xiě)的枚舉,以避免實(shí)例化 |
| custom_rules | no | no | no | style | no | user-defined | 通過(guò)提供正則表達(dá)式字符串來(lái)創(chuàng)建自定義規(guī)則 |
| cyclomatic_complexity | no | no | yes | metrics | no | warning: 10, error: 20, ignores_case_statements: false | 代碼復(fù)雜度,默認(rèn)為10,循環(huán)復(fù)雜度。函數(shù)體的復(fù)雜度的限制,這個(gè)屬性主要約束條件句、循環(huán)句中的循環(huán)嵌套問(wèn)題, 當(dāng)嵌套太多的循環(huán)時(shí),則會(huì)觸發(fā)swiftlint中的warning和error,當(dāng)達(dá)到10個(gè)循環(huán)嵌套時(shí)就會(huì)報(bào)warning,達(dá)到20個(gè)循環(huán)嵌套時(shí)就會(huì)報(bào)error,強(qiáng)烈推薦這個(gè)屬性。嵌套太多,可讀性差 |
| deployment_target | no | no | yes | lint | no | warning, iOS_deployment_target: 7.0, macOS_deployment_target: 1... | - |
| discarded_notification_center_observer | yes | no | no | lint | no | warning | 當(dāng)使用 block 注冊(cè)通知中心 observer 的時(shí)候, 應(yīng)該存儲(chǔ)函數(shù)返回的 observer, 以便之后的刪除 |
| discouraged_assert | yes | no | no | idiomatic | no | warning | - |
| discouraged_direct_init | no | no | yes | lint | no | warning, types: ["Bundle", "Bundle.init", "UIDevice", "UIDevice... | 不鼓勵(lì)直接初始化并聲明的類(lèi)型 warning:types: ["Bundle", "Bundle.init", "UIDevice", "UIDevice.init"] |
| discouraged_object_literal | yes | no | no | idiomatic | no | warning, image_literal: true, color_literal: true | 避免使用圖片和顏色的字面量(Ltiteral),盡量使用初始化的方式 |
| discouraged_optional_boolean | yes | no | no | idiomatic | no | warning | 推薦使用非可選的bool值 |
| discouraged_optional_collection | yes | no | no | idiomatic | no | warning | 優(yōu)先選擇空集合而不是可選集合 |
| duplicate_enum_cases | no | no | yes | lint | no | error | 枚舉不能設(shè)置兩個(gè)或者以上相同的名字 |
| duplicate_imports | no | no | yes | idiomatic | no | warning | 重復(fù)導(dǎo)入 |
| dynamic_inline | no | no | yes | lint | no | error | 避免同時(shí)使用'dynamic'和'@inline(__ always)' |
| empty_count | yes | no | no | performance | no | error, only_after_dot: false | 建議使用isEmpty判斷,而不是使用count==0判斷 |
| empty_enum_arguments | no | yes | yes | style | no | warning | 如果將枚舉與關(guān)聯(lián)的類(lèi)型匹配(如果不使用),則可以忽略參數(shù) |
| empty_parameters | no | yes | yes | style | no | warning | 使用 () -> 代替 `Void -> |
| empty_parentheses_with_trailing_closure | no | yes | yes | style | no | warning | 尾閉包避免空參數(shù)括號(hào) |
| empty_string | yes | no | no | performance | no | warning | 優(yōu)先使用isEmpty判斷,而不是將字符串與空字符串文字進(jìn)行比較 |
| empty_xctest_method | yes | no | no | lint | no | warning | 應(yīng)避免使用空的XCTest方法 |
| enum_case_associated_values_count | yes | no | no | metrics | no | warning: 5, error: 6 | 枚舉情況下的關(guān)聯(lián)值數(shù)量應(yīng)少 |
| expiring_todo | yes | no | no | lint | no | (approaching_expiry_severity) warning, (reached_or_passed_expir... | TODO和FIXME應(yīng)該在其到期日之前解決 |
| explicit_acl | yes | no | no | idiomatic | no | warning | 所有聲明都應(yīng)明確指定訪問(wèn)控制級(jí)別關(guān)鍵字 |
| explicit_enum_raw_value | yes | no | no | idiomatic | no | warning | 枚舉應(yīng)設(shè)置默認(rèn)值 |
| explicit_init | yes | yes | no | idiomatic | no | warning | 避免直接調(diào)用 init 方法 |
| explicit_self | yes | yes | no | style | yes | warning | 實(shí)例變量和函數(shù)應(yīng)使用“self”顯式訪問(wèn) |
| explicit_top_level_acl | yes | no | no | idiomatic | no | warning | 頂級(jí)聲明應(yīng)明確指定訪問(wèn)控制級(jí)別關(guān)鍵字 |
| explicit_type_interface | yes | no | no | idiomatic | no | warning, excluded: [], allow_redundancy: false | 需要跑明確參數(shù)的類(lèi)型定義 |
| extension_access_modifier | yes | no | no | idiomatic | no | warning | 優(yōu)先使用擴(kuò)展名訪問(wèn)修飾符 |
| fallthrough | yes | no | no | idiomatic | no | warning | 避免在 case語(yǔ)句中使用 fallthrough |
| fatal_error_message | yes | no | no | idiomatic | no | warning | 必須擁有一個(gè) message |
| file_header | yes | no | no | style | no | warning, required_string: None, required_pattern: None, forbidd... | 標(biāo)頭注釋?xiě)?yīng)與項(xiàng)目模式一致 |
| file_length | no | no | yes | metrics | no | warning: 400, error: 1000, ignore_comment_only_lines: false | 文件長(zhǎng)度限制 |
| file_name | yes | no | no | idiomatic | no | (severity) warning, excluded: ["LinuxMain.swift", "main.swift"]... | 文件名應(yīng)與文件中聲明的類(lèi)型或擴(kuò)展名匹配(如果有 |
| file_types_order | yes | no | no | style | no | warning, order: [[SwiftLintFramework.FileType.supportingType], ... | 指定如何排序文件中的類(lèi)型 |
| first_where | yes | no | no | performance | no | warning | 使用 .first(where:) 代替 .filter { }.first
|
| flatmap_over_map_reduce | yes | no | no | performance | no | warning | 推薦使用 flatMap,避免使用 map 的 reduce([], +) |
| for_where | no | no | yes | idiomatic | no | warning | 使用 for where 代替 簡(jiǎn)單的 for { if }
|
| force_cast | no | no | yes | idiomatic | no | error | 避免強(qiáng)制的類(lèi)型轉(zhuǎn)化,這里表示強(qiáng)解類(lèi)型警告 as! Int |
| force_try | no | no | yes | idiomatic | no | error | 對(duì)會(huì)拋出異常(throws)的方法,不建議try,強(qiáng)解, 避免 try!
|
| force_unwrapping | yes | no | no | idiomatic | no | warning | 避免強(qiáng)制解包 |
| function_body_length | no | no | yes | metrics | no | warning: 40, error: 100 | 函數(shù)體長(zhǎng)度 默認(rèn)超過(guò)40行warning,超過(guò)100行直接報(bào)錯(cuò)。推薦使用 |
| function_default_parameter_at_end | yes | no | no | idiomatic | no | warning | 方法中參數(shù)列表,應(yīng)將帶有默認(rèn)值的參數(shù)放在最后面 |
| function_parameter_count | no | no | yes | metrics | no | warning: 5, error: 8ignores_default_parameters: true | 函數(shù)參數(shù)個(gè)數(shù) |
| generic_type_name | no | no | yes | idiomatic | no | (min_length) w/e: 1/0, (max_length) w/e: 20/1000, excluded: [],... | 類(lèi)型命名規(guī)則限制,以大寫(xiě)字母開(kāi)頭,且長(zhǎng)度在1到20個(gè)字符之間 |
| ibinspectable_in_extension | yes | no | no | lint | no | warning | 擴(kuò)展不應(yīng)添加@IBInspectable屬性 |
| identical_operands | yes | no | no | lint | no | warning | 比較兩個(gè)相同的操作數(shù)可能是一個(gè)錯(cuò)誤 |
| identifier_name | no | no | yes | style | no | (min_length) w/e: 3/2, (max_length) w/e: 40/60, excluded: [], a... | 參數(shù)變量命名規(guī)則 |
| implicit_getter | no | no | yes | style | no | warning | 參數(shù)不應(yīng)該有 getter 方法 |
| implicit_return | yes | yes | no | style | no | warning, included: [getter, closure, function] | 在閉包,函數(shù)和getter中更喜歡隱式返回 |
| implicitly_unwrapped_optional | yes | no | no | idiomatic | no | warning, mode: allExceptIBOutlets | 避免隱式解析可選類(lèi)型的使用 / 避免隱式解包(定義 ! 類(lèi)型) |
| inclusive_language | no | no | yes | style | no | warning, additional_terms: [], override_terms: [], override_all... | |
| inert_defer | no | no | yes | lint | no | warning | 如果defer在其父范圍的末尾,則無(wú)論如何它都會(huì)被執(zhí)行 |
| is_disjoint | no | no | yes | idiomatic | no | warning | 優(yōu)先:Set.isDisjoint(with:) 不建議:Set.intersection(_:).isEmpty |
| joined_default_parameter | yes | yes | no | idiomatic | no | warning | 不推薦顯式使用默認(rèn)分隔符 |
| large_tuple | no | no | yes | metrics | no | warning: 2, error: 3 | 元祖成員 元組沖突:元組應(yīng)該最多有2個(gè)成員,多余兩個(gè)會(huì)報(bào)錯(cuò) |
| last_where | yes | no | no | performance | no | warning | 推薦在集合中使用:.last(where:) 不推薦使用: .filter { }.last |
| leading_whitespace | no | yes | yes | style | no | warning | 文件末尾不應(yīng)該存在空格符 |
| legacy_cggeometry_functions | no | yes | yes | idiomatic | no | warning | 避免使用 C 風(fēng)格 的 CG 遺留函數(shù), 使用 struct extension |
| legacy_constant | no | yes | yes | idiomatic | no | warning | 避免使用 遺留的全局常量, 使用 struct 內(nèi)定義的 常量 |
| legacy_constructor | no | yes | yes | idiomatic | no | warning | 使用 swift 提供的 struct 構(gòu)造函數(shù), 避免使用 遺留的構(gòu)造函數(shù) 比如 CGPointMake(10, 10) |
| legacy_hashing | no | no | yes | idiomatic | no | warning | hash(into:)優(yōu)先使用函數(shù)而不是覆蓋hashValue |
| legacy_multiple | yes | no | no | idiomatic | no | warning | 推薦使用isMultiple(of:)函數(shù),不推薦使用余數(shù)運(yùn)算符(%) |
| legacy_nsgeometry_functions | no | yes | yes | idiomatic | no | warning | 避免使用 C 風(fēng)格 的 NS 遺留函數(shù), 使用 struct extension |
| legacy_objc_type | yes | no | no | idiomatic | no | warning | - |
| legacy_random | yes | no | no | idiomatic | no | warning | 隨機(jī)函數(shù) 優(yōu)先使用type.random(in :),不建議使用舊版函數(shù) |
| let_var_whitespace | yes | no | no | style | no | warning | let和var應(yīng)該用空白行與其他語(yǔ)句分開(kāi) |
| line_length | no | no | yes | metrics | no | warning: 120, error: 200, ignores urls: false, ignores function... | 行的字符長(zhǎng)度,官方的規(guī)定是超過(guò)120字符就給 warning |
| literal_expression_end_indentation | yes | yes | no | style | no | warning | 數(shù)組和字典文字的結(jié)尾應(yīng)與開(kāi)始它的行具有相同的縮進(jìn) |
| lower_acl_than_parent | yes | no | no | lint | no | warning | 確保定義的訪問(wèn)控制級(jí)別低于其父級(jí) |
| mark | no | yes | yes | lint | no | warning | 正確使用 mark 的格式 // MARK: - message
|
| missing_docs | yes | no | no | lint | no | warning: open, public | 聲明應(yīng)記錄在案 |
| modifier_order | yes | yes | no | style | no | warning, preferred_modifier_order: [override, acl, setterACL, d... | 修飾符順序應(yīng)一致 |
| multiline_arguments | yes | no | no | style | no | warning, first_argument_location: any_line, only_enforce_after_... | 參數(shù)應(yīng)該在同一行,或者每行一個(gè) |
| multiline_arguments_brackets | yes | no | no | style | no | warning | 多行參數(shù)應(yīng)在其新行中包含方括號(hào) [] |
| multiline_function_chains | yes | no | no | style | no | warning | 鏈接的函數(shù)調(diào)用應(yīng)該在同一行上,或者每行一個(gè) |
| multiline_literal_brackets | yes | no | no | style | no | warning | 多行文字應(yīng)在其新行中包含方括號(hào) [] |
| multiline_parameters | yes | no | no | style | no | warning, allowsSingleLine: true | 函數(shù)和方法參數(shù)應(yīng)該在同一行上,或者每行一個(gè) |
| multiline_parameters_brackets | yes | no | no | style | no | warning | 多行參數(shù)應(yīng)在其新行中包含方括號(hào) |
| multiple_closures_with_trailing_closure | no | no | yes | style | no | warning | 傳遞多個(gè)閉包參數(shù)時(shí),不應(yīng)使用結(jié)尾的閉包語(yǔ)法 |
| nesting | no | no | yes | metrics | no | (type_level) w: 1, (function_level) w: 2, (check_nesting_in_clo... | 類(lèi)型定義嵌套不要超過(guò)1層 , 聲明嵌套不要超過(guò)5層 |
| nimble_operator | yes | yes | no | idiomatic | no | warning | 避免 expect 一個(gè)確定的判斷 |
| no_extension_access_modifier | yes | no | no | idiomatic | no | error | 禁止使用擴(kuò)展訪問(wèn)修飾符 |
| no_fallthrough_only | no | no | yes | idiomatic | no | warning | 僅當(dāng)case包含至少一個(gè)其他語(yǔ)句時(shí),才能使用穿透 |
| no_grouping_extension | yes | no | no | idiomatic | no | warning | 擴(kuò)展名不應(yīng)用于對(duì)同一源文件中的代碼進(jìn)行分組 |
| no_space_in_method_call | no | yes | yes | style | no | warning | 不要在方法名稱(chēng)和括號(hào)之間添加空格 |
| notification_center_detachment | no | no | yes | lint | no | warning |
NotificationCenter.default.removeObserver 只在 deinit 中被調(diào)用 |
| nslocalizedstring_key | yes | no | no | lint | no | warning | 應(yīng)將靜態(tài)字符串用作NSLocalizedString中的鍵 |
| nslocalizedstring_require_bundle | yes | no | no | lint | no | warning | 調(diào)用NSLocalizedString應(yīng)該指定包含字符串文件的捆綁軟件 |
| nsobject_prefer_isequal | no | no | yes | lint | no | warning | NSObject子類(lèi)應(yīng)實(shí)現(xiàn)isEqual而不是== |
| number_separator | yes | yes | no | style | no | warning, minimum_length: 0 | 使用 _ 分割大數(shù), 讓數(shù)字更清晰 |
| object_literal | yes | no | no | idiomatic | no | warning, image_literal: true, color_literal: true | 避免 image and color 使用字面量初始化, 需要把相關(guān)圖片名,顏色RGB 等參數(shù)定義為 enum struct 或者常量 |
| opening_brace | no | yes | yes | style | no | warning, allowMultilineFunc: false | 右括號(hào)之前應(yīng)有一個(gè)空格,并與聲明在同一行 |
| operator_usage_whitespace | yes | yes | no | style | no | warning, lines_look_around: 2, skip_aligned_constants: true | 操作符需要使用一個(gè)空格間隔 |
| operator_whitespace | no | no | yes | style | no | warning | 當(dāng)定義空格操作符的時(shí)候,被定義的名字或類(lèi)型兩邊應(yīng)該各有一個(gè)單行空格操作符 |
| optional_enum_case_matching | yes | yes | no | style | no | warning | 將枚舉大小寫(xiě)與不帶'?'的可選枚舉匹配 在Swift 5.1及更高版本中受支持 |
| orphaned_doc_comment | no | no | yes | lint | no | warning | 注釋要寫(xiě)在聲明中 |
| overridden_super_call | yes | no | no | lint | no | warning, excluded: [], included: ["*"] | 方法需要調(diào)用 super method |
| override_in_extension | yes | no | no | lint | no | warning | 擴(kuò)展不應(yīng)覆蓋聲明 |
| pattern_matching_keywords | yes | no | no | idiomatic | no | warning | 通過(guò)將關(guān)鍵字移出元組來(lái)組合多個(gè)模式匹配綁定 |
| prefer_nimble | yes | no | no | idiomatic | no | warning | |
| prefer_self_type_over_type_of_self | yes | yes | no | style | no | warning | 訪問(wèn)屬性或調(diào)用方法時(shí),最好將“自類(lèi)型”設(shè)置為(of:self) |
| prefixed_toplevel_constant | yes | no | no | style | no | warning, only_private: false | 頂級(jí)常量的前綴應(yīng)為k |
| private_action | yes | no | no | lint | no | warning | IBActions應(yīng)該是私有的 |
| private_outlet | yes | no | no | lint | no | warning, allow_private_set: false | IBOutlets 應(yīng)該設(shè)置為 private, 來(lái)避免泄露 |
| private_over_fileprivate | no | yes | yes | idiomatic | no | warning, validate_extensions: false | 推薦:private 不建議:fileprivate |
| private_subject | yes | no | no | lint | no | warning | - |
| private_unit_test | no | no | yes | lint | no | warning: XCTestCase | 單元測(cè)試方法 不能設(shè)置為 private |
| prohibited_interface_builder | yes | no | no | lint | no | warning | 禁止用interface Builder 創(chuàng)建視圖 |
| prohibited_super_call | yes | no | no | lint | no | warning, excluded: [[]], included: [["*"]] | 某些特殊的 override 方法, 禁止調(diào)用 super method excluded: [[]], included: [["*"]] |
| protocol_property_accessors_order | no | yes | yes | style | no | warning | 在協(xié)議中聲明屬性 要按順序先寫(xiě) get set方法 |
| quick_discouraged_call | yes | no | no | lint | no | warning | 不鼓勵(lì)在“describe”和/或“context” 框中進(jìn)行調(diào)用 |
| quick_discouraged_focused_test | yes | no | no | lint | no | warning | 不鼓勵(lì)重點(diǎn)測(cè)試。專(zhuān)注于此測(cè)試時(shí),其他測(cè)試將不會(huì)運(yùn)行 |
| quick_discouraged_pending_test | yes | no | no | lint | no | warning | 不推薦:未開(kāi)始的測(cè)試。標(biāo)記為待定時(shí),該測(cè)試不會(huì)運(yùn)行 |
| raw_value_for_camel_cased_codable_enum | yes | no | no | lint | no | warning | 設(shè)置枚舉建議設(shè)置默認(rèn)值 |
| reduce_boolean | no | no | yes | performance | no | warning | 優(yōu)先使用.allSatisfy()或.contains() 不建議使用:reduce(true)或reduce(false) |
| reduce_into | yes | no | no | performance | no | warning | 對(duì)于 copy-on-write 類(lèi)型,推薦使用 reduce(into::) 不建議使用 reduce(:_:) |
| redundant_discardable_let | no | yes | yes | style | no | warning | 使用 _ = foo() 代替 let _ = foo()
|
| redundant_nil_coalescing | yes | yes | no | idiomatic | no | warning | #避免使用 object ?? nil 僅當(dāng)lhs為nil時(shí)才評(píng)估nil合并運(yùn)算符,而n為rhs則合并nil合并運(yùn)算符 |
| redundant_objc_attribute | no | yes | yes | idiomatic | no | warning | Objective-C屬性(@objc)在聲明中是多余的 |
| redundant_optional_initialization | no | yes | yes | idiomatic | no | warning | 用nil初始化可選變量是多余的。 # 默認(rèn)值賦值為nil 不需要寫(xiě)默認(rèn)值為 nil |
| redundant_set_access_control | no | no | yes | idiomatic | no | warning | 如果屬性設(shè)置程序訪問(wèn)級(jí)別與變量訪問(wèn)級(jí)別相同,則不應(yīng)明確 |
| redundant_string_enum_value | no | no | yes | idiomatic | no | warning | 在定義字符串枚舉的時(shí)候, 當(dāng)字符串枚舉值等于枚舉名稱(chēng)時(shí),可以不用賦值 |
| redundant_type_annotation | yes | yes | no | idiomatic | no | warning | 變量不應(yīng)具有冗余類(lèi)型注釋 建議 var url = URL() 不建議 var url : URL = URL() |
| redundant_void_return | no | yes | yes | idiomatic | no | warning | 在函數(shù)聲明中返回Void是多余的。#在不必要的時(shí)候, 不需要寫(xiě) ->() and -> Void |
| required_deinit | yes | no | no | lint | no | warning | 類(lèi)應(yīng)具有顯式的deinit方法 |
| required_enum_case | yes | no | no | lint | no | No protocols configured. In config add 'required_enum_case' to... | 符合指定協(xié)議的枚舉必須實(shí)現(xiàn)特定情況 |
| return_arrow_whitespace | no | yes | yes | style | no | warning | 前后要有空格,函數(shù)定義返回的 -> 前后有空格, 不換行 |
| shorthand_operator | no | no | yes | style | no | error | 使用+= , -=, *=, /= 代替 a = a + 1 |
| single_test_class | yes | no | no | style | no | warning | 測(cè)試文件應(yīng)只包含一個(gè)QuickSpec或XCTestCase類(lèi) |
| sorted_first_last | yes | no | no | performance | no | warning | 優(yōu)先使用min()或max() 不建議使用 sorted().first或sorted().last |
| sorted_imports | yes | yes | no | style | no | warning | Imports 應(yīng)排序 |
| statement_position | no | yes | yes | style | no | (statement_mode) default, (severity) warning | 這里主要指的是 else 和 catch 前面要加一個(gè)空格, 也不能大于1個(gè)空格 |
| static_operator | yes | no | no | idiomatic | no | warning | 應(yīng)該將運(yùn)算符聲明為靜態(tài)函數(shù),而不是自由函數(shù) |
| strict_fileprivate | yes | no | no | idiomatic | no | warning | fileprivate 應(yīng)該避免 |
| strong_iboutlet | yes | yes | no | lint | no | warning | @IBOutlets不應(yīng)被聲明為weak 應(yīng)該為 strong |
| superfluous_disable_command | no | no | yes | lint | no | warning | 當(dāng)禁用規(guī)則不會(huì)在禁用區(qū)域觸發(fā)違規(guī)時(shí),SwiftLint的“禁用”命令是多余的。如果要記錄命令,請(qǐng)使用“-” |
| switch_case_alignment | no | no | yes | style | no | warning, indented_cases: false | Case語(yǔ)句應(yīng)與其封閉的switch語(yǔ)句垂直對(duì)齊,如果沒(méi)有其他配置,則縮進(jìn) |
| switch_case_on_newline | yes | no | no | style | no | warning | switch 的 case 需要新啟一行 |
| syntactic_sugar | no | yes | yes | idiomatic | no | warning | 語(yǔ)法糖[Int] 代替Array / 例:要使用 [] ? 等數(shù)組字典可選項(xiàng)的語(yǔ)法糖 |
| test_case_accessibility | yes | yes | no | lint | no | warning, allowed_prefixes: [[]] | - |
| todo | no | no | yes | lint | no | warning | 避免 TODOs and FIXMEs 標(biāo)識(shí) |
| toggle_bool | yes | yes | no | idiomatic | no | warning | 不讓使用 A = !A 建議使用 A.toggle() |
| trailing_closure | yes | no | no | style | no | warning, only_single_muted_parameter: false | 盡可能使用尾隨閉包語(yǔ)法 |
| trailing_comma | no | yes | yes | style | no | warning, mandatory_comma: false | 數(shù)組末尾不要加空格 |
| trailing_newline | no | yes | yes | style | no | warning | 末尾空行,文件末尾應(yīng)該有一個(gè)空行 |
| trailing_semicolon | no | yes | yes | idiomatic | no | warning | 行末尾不加分號(hào) |
| trailing_whitespace | no | yes | yes | style | no | warning, ignores_empty_lines: false, ignores_comments: true | 每一個(gè)空行不能有空格 |
| type_body_length | no | no | yes | metrics | no | warning: 200, error: 350 | 類(lèi)型體長(zhǎng)度不應(yīng)該跨越太多行,超過(guò)200行給warning,超過(guò)350行給error |
| type_contents_order | yes | no | no | style | no | warning, order: [[SwiftLintFramework.TypeContent.case], [SwiftL... | 指定類(lèi)型內(nèi)子類(lèi)型,屬性,方法及更多內(nèi)容的順序 |
| type_name | no | no | yes | idiomatic | no | (min_length) w/e: 3/0, (max_length) w/e: 40/1000, excluded: [],... | 類(lèi)型名字限制規(guī)則,類(lèi)型名稱(chēng)只能包含字母數(shù)字字符,以大寫(xiě)字母開(kāi)頭,并且長(zhǎng)度在3到40個(gè)字符之間 |
| unavailable_function | yes | no | no | idiomatic | no | warning | 未實(shí)現(xiàn)的功能應(yīng)標(biāo)記為不可用 |
| unneeded_break_in_switch | no | no | yes | idiomatic | no | warning | 在switch-case語(yǔ)句中, 有方法調(diào)用或操作時(shí),避免使用break語(yǔ)句 |
| unneeded_parentheses_in_closure_argument | yes | yes | no | style | no | warning | 聲明閉包參數(shù)時(shí),不需要括號(hào) |
| unowned_variable_capture | yes | no | no | lint | no | warning | 最好將引用捕獲為弱引用以避免潛在的崩潰 |
| untyped_error_in_catch | yes | yes | no | idiomatic | no | warning | 沒(méi)有類(lèi)型轉(zhuǎn)換,catch語(yǔ)句不應(yīng)聲明錯(cuò)誤變量 |
| unused_capture_list | no | no | yes | lint | no | warning | 閉包中沒(méi)有被使用的參數(shù)應(yīng)該刪除 |
| unused_closure_parameter | no | yes | yes | lint | no | warning | 函數(shù)的參數(shù)必須被使用 |
| unused_control_flow_label | no | yes | yes | lint | no | warning | 未使用的控制流標(biāo)簽應(yīng)被刪除 |
| unused_declaration | yes | no | no | lint | yes | severity: error, include_public_and_open: false, related_usrs_t... | 在所有被刪除的文件中,聲明至少應(yīng)被引用一次 |
| unused_enumerated | no | no | yes | idiomatic | no | warning | 默認(rèn)-當(dāng)參數(shù)沒(méi)有被全部使用的時(shí)候, 不要使用容器的 enumerated 方法 |
| unused_import | yes | yes | no | lint | yes | severity: warning, require_explicit_imports: false, allowed_tra... | import 的文件要被使用 |
| unused_optional_binding | no | no | yes | style | no | warning, ignore_optional_try: false | 在使用if判斷某變量是否為nil的時(shí)候, 不建議使用下劃線(xiàn)(_) 必須使用定義的 optional binding |
| unused_setter_value | no | no | yes | lint | no | warning | 不使用設(shè)定值 |
| valid_ibinspectable | no | no | yes | lint | no | warning | 默認(rèn)-IBInspectable 必須是可變參數(shù) |
| vertical_parameter_alignment | no | no | yes | style | no | warning | 函數(shù)參數(shù)分為多行書(shū)寫(xiě)的時(shí)候, 頭部(小括號(hào)后面一位)必須對(duì)齊 函數(shù)參數(shù)分為多行書(shū)寫(xiě)的時(shí)候, 頭部(小括號(hào)后面一位)必須對(duì)齊 |
| vertical_parameter_alignment_on_call | yes | no | no | style | no | warning | 如果函數(shù)參數(shù)在方法調(diào)用中位于多行中,則應(yīng)垂直對(duì)齊 |
| vertical_whitespace | no | yes | yes | style | no | warning, max_empty_lines: 1 | 垂直方向上的空格行,限制為一行(注釋除外) 不能有連續(xù)多個(gè)空行 |
| vertical_whitespace_between_cases | yes | yes | no | style | no | warning | 在 switch cases 之間包括一條空行 |
| vertical_whitespace_closing_braces | yes | yes | no | style | no | N/A | 在關(guān)閉大括號(hào)之前,請(qǐng)勿包括垂直空格(空行) |
| vertical_whitespace_opening_braces | yes | yes | no | style | no | N/A | 打開(kāi)花括號(hào)后,請(qǐng)勿包括垂直空格(空行) |
| void_return | no | yes | yes | style | no | warning | - |
| weak_delegate | no | yes | yes | lint | no | warning | 代理要設(shè)置為弱引用 |
| xct_specific_matcher | yes | no | no | idiomatic | no | warning | 優(yōu)先使用特定的XCTest匹配器,XCTAssertEqual而不是XCTAssertNotEqual |
| xctfail_message | no | no | yes | idiomatic | no | warning | XCTFail調(diào)用應(yīng)包括斷言的描述,描述不能為空 |
| yoda_condition | yes | no | no | lint | no | warning | 變量應(yīng)位于比較運(yùn)算符的左側(cè),常數(shù)應(yīng)位于右側(cè) |