SwiftLintの記事はシリーズになっています。
記事を順番に読み進めると、SwiftLintを使いこなせるようになります。
- Swiftの静的解析ツール「SwiftLint」のセットアップ方法
- SwiftLintの全ルール一覧(Swift 4.2版) ←イマココ
- SwiftLintで追加・変更・廃止されたルールまとめ(Swift 4.2→5.1.2版)
- SwiftLintで追加・廃止されたルールまとめ(Swift 5.1.2→5.3.1版)
- SwiftLintのオレオレカスタムルール一覧
- SwiftLintのAnalyzeを使って高度な解析をする方法
- SwiftLintの設定ファイルをサーバーに配置して共有する方法
- SwiftLintの「Currently running SwiftLint x.y.z but configuration specified version a.b.c.」エラーの解決法
はじめに
すでに SwiftLintのルールをまとめてくださっている方 がいらっしゃいますが、約2年ほど更新されていなかったので、自分でもまとめてみました。
SwiftLintの概要や導入については以下をご参照ください。
Swiftの静的解析ツール「SwiftLint」のセットアップ方法 - Qiita
2019/12/08 追記
今回紹介するSwiftLintのバージョン(0.30.1)から0.38.0までの間に、追加・変更・廃止されたルールを以下の記事にまとめました。
https://qiita.com/uhooi/items/8e9767c2e746f4171ded
SwiftLintの最新バージョンを使う方は併せてご参照ください。
注意
公式ページのルールを簡単に翻訳してまとめたものです。
英語に慣れている方は公式ページを直接見るのがいいです。
https://github.com/realm/SwiftLint/blob/master/Rules.md
また、間違っている箇所や不適切な箇所がありましたら教えていただけると嬉しいです。
環境
- Swift:4.2.1
- Xcode:10.1 (10B61)
- SwiftLint:0.30.1
Default
デフォルトで有効になっているルールの一覧です。
Block Based KVO
Swift 3.2以降の場合、新しいブロックベースのKVO APIとキーパスを使うべきです。
https://realm.github.io/SwiftLint/block_based_kvo.html
// bad
class Foo: NSObject {
override func observeValue(forKeyPath keyPath: String?, of object: Any?,
change: [NSKeyValueChangeKey: Any]?,
context: UnsafeMutableRawPointer?) { }
}
// good
let observer = foo.observe(\.value, options: [.new]) { (foo, change) in
print(change.newValue)
}
Class Delegate Protocol
デリゲートプロトコルはクラスのみであるべきで、弱参照されることができます。
https://realm.github.io/SwiftLint/class_delegate_protocol.html
// bad
protocol FooDelegate { }
// good
protocol FooDelegate: class { }
Closing Brace Spacing
右括弧で閉じ括弧を閉じる場合、間にスペースを含めるべきではありません。
https://realm.github.io/SwiftLint/closing_brace_spacing.html
// bad
[].map({ } )
// good
[].map({ })
Closure Parameter Position
クロージャのパラメータは開き括弧と同じ行にあるべきです。
https://realm.github.io/SwiftLint/closure_parameter_position.html
// bad
[1, 2].map {
number in
number + 1
}
// good
[1, 2].map { number in
number + 1
}
Colon
:
は、型の指定時には識別子の後ろ、ディクショナリではキーの後ろにあるべきです。
https://realm.github.io/SwiftLint/colon
// bad
let abc:Void
let abc :Void
let abc : Void
let abc: [String:Int]
let abc: [String :Int]
let abc: [String : Int]
// good
let abc: Void
let abc: [String: Int]
Comma Spacing
カンマの前にスペースがあるべきではなく、カンマの後ろには1つの半角スペースがあるべきです。
https://realm.github.io/SwiftLint/comma_spacing.html
// bad
func abc(a: String,b: String) { }
func abc(a: String ,b: String) { }
func abc(a: String , b: String) { }
// good
func abc(a: String, b: String) { }
Compiler Protocol Init
ExpressibleByArrayLiteral
のようなコンパイルプロトコルで定義されているイニシャライザは直接呼び出すべきではありません。
https://realm.github.io/SwiftLint/compiler_protocol_init.html
// bad
let set = Set(arrayLiteral: 1, 2)
let set = Set.init(arrayLiteral: 1, 2)
// good
let set: Set<Int> = [1, 2]
let set = Set(array)
Control Statement
if
, for
, guard
, switch
, while
, catch
文は条件や引数を不必要に括弧で括るべきではありません。
https://realm.github.io/SwiftLint/control_statement.html
// bad
if (condition) { }
for (item in collection) { }
guard (condition) else { }
switch (foo) { }
while (condition) { }
do {
} catch (let error) {
}
// good
if condition { }
for item in collection { }
guard condition else { }
switch foo { }
while condition { }
do {
} catch let error {
}
Custom Rules
正規表現を指定してカスタムルールを作成できます。
https://realm.github.io/SwiftLint/custom_rules.html
Cyclomatic Complexity
関数内は複雑にすべきではありません。
https://realm.github.io/SwiftLint/cyclomatic_complexity.html
// bad
func f1() {
if true {
if true {
if false { }
}
}
if false { }
let i = 0
switch i {
case 1: break
case 2: break
case 3: break
case 4: break
default: break
}
for _ in 1...5 {
guard true else {
return
}
}
}
// good
func f1() {
if true {
for _ in 1..5 { } }
if false { }
}
Deployment Target
可用性のチェックまたは属性は、デプロイメントターゲットが満たす古いバージョンを使うべきではありません。
https://realm.github.io/SwiftLint/deployment_target.html
// bad
@available(iOS 6.0, *)
class A { }
if #available(iOS 6.0, *) { }
// good
@available(iOS 12.0, *)
class A { }
if #available(iOS 12.0, *) { }
Discarded Notification Center Observer
ブロックを使って通知を登録するとき、返される不透明なオブザーバは後で削除できるように格納すべきです。
https://realm.github.io/SwiftLint/discarded_notification_center_observer.html
// bad
nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil) { }
// good
let foo = nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil) { }
Discouraged Direct Initialization
有害な可能性がある型を直接初期化すべきではありません。
https://realm.github.io/SwiftLint/discouraged_direct_initialization.html
// bad
let foo = UIDevice()
let foo = Bundle()
// good
let foo = UIDevice.current
let foo = Bundle.main
let foo = Bundle(path: "bar")
let foo = Bundle(identifier: "bar")
Duplicate Imports
インポートは1回のみ行うべきです。
https://realm.github.io/SwiftLint/duplicate_imports.html
// bad
import Foundation
import Dispatch
import Foundation
// good
import Foundation
import Dispatch
Dynamic Inline
dynamic
と @inline(__always)
を同時に使ってはいけません。
https://realm.github.io/SwiftLint/dynamic_inline.html
// bad
class C {
@inline(__always) dynamic func f() { }
}
// good
class C {
dynamic func f() { }
}
class C {
@inline(__always) func f() { }
}
Empty Enum Arguments
列挙型が連想型と一致しない場合、引数を省略すべきです。
https://realm.github.io/SwiftLint/empty_enum_arguments.html
// bad
switch foo {
case .bar(_): break
}
switch foo {
case .bar(): break
}
// good
switch foo {
case .bar: break
}
Empty Parameters
Void ->
より () ->
を使うべきです。
https://realm.github.io/SwiftLint/empty_parameters.html
// bad
let abc: (Void) -> Void = { }
// good
let abc: () -> Void = { }
Empty Parentheses with Trailing Closure
トレイリングクロージャを使う場合、メソッドの呼び出し後に空の括弧を記述すべきではありません。
https://realm.github.io/SwiftLint/empty_parentheses_with_trailing_closure.html
// bad
[1, 2].map() { $0 + 1 }
// good
[1, 2].map { $0 + 1 }
File Line Length
ファイル内はあまりにも多くの行にまたがるべきではないです。
https://realm.github.io/SwiftLint/file_line_length.html
// bad
print("swiftlint")
print("swiftlint")
print("swiftlint")
…
For Where
for文内にif文が1つのみ存在する場合、 where
句を使うべきです。
https://realm.github.io/SwiftLint/for_where.html
// bad
for user in users {
if user.id == 1 {
user.myFunction()
}
}
// good
for user in users where user.id == 1 {
user.myFunction()
}
Force Cast
強制キャスト( as!
)は使うべきではありません。
https://realm.github.io/SwiftLint/force_cast.html
// bad
NSNumber() as! Int
// good
NSNumber() as? Int
Force Try
強制トライ( try!
)は使うべきではありません。
https://realm.github.io/SwiftLint/force_try.html
func a() throws { }
// bad
try! a()
// good
do {
try a()
} catch {
// エラー処理
}
Function Body Length
関数内はあまりにも多くの行にまたがるべきではないです。
https://realm.github.io/SwiftLint/function_body_length.html
Function Parameter Count
関数の引数の数は少なくすべきです。
https://realm.github.io/SwiftLint/function_parameter_count.html
// bad
func f(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) { }
// good
func f(a: Int, b: Int, c: Int, d: Int, e: Int) { }
Generic Type Name
ジェネリック型は英数のみを含み、大文字で始まり、1〜20文字にすべきです。
https://realm.github.io/SwiftLint/generic_type_name.html
// bad
func foo<T, U_Foo>(param: U_Foo) -> T { }
func foo<T, u>(param: u) -> T { }
// good
func foo<T, U>(param: U) -> T { }
Identifier Name
識別子名は英数のみを含み、小文字で始まるか、大文字のみを含むべきです。
上記以外では、変数名は静的かつ不変と定義されている場合は大文字から始まることがあります。
変数名は長過ぎたり短過ぎたりしてはいけません。
https://realm.github.io/SwiftLint/identifier_name.html
// bad
let MyLet = 0
let _myLet = 0
let id = 0
// good
let myLet = 0
Implicit Getter
読取専用のコンピューテッドプロパティとサブスクリプトには get
キーワードを使うべきではありません。
https://realm.github.io/SwiftLint/implicit_getter.html
// bad
class Foo {
var foo: Int {
get {
return 20
}
}
}
// good
class Foo {
var foo: Int {
return 20
}
}
Inert Defer
defer
が親スコープの終わりにある場合、その場所で実行されます。
https://realm.github.io/SwiftLint/inert_defer.html
// bad
func example() {
print("other code")
defer { /* deferred code */ }
}
// good
func example() {
defer { /* deferred code */ }
print("other code")
}
Is Disjoint
Set.intersection(_:).isEmpty
より Set.isDisjoint(with:)
を使うべきです。
https://realm.github.io/SwiftLint/is_disjoint.html
// bad
_ = Set(syntaxKinds).intersection(commentAndStringKindsSet).isEmpty
// good
_ = Set(syntaxKinds).isDisjoint(with: commentAndStringKindsSet)
Large Tuple
タプルはあまりにも多くのメンバーを持つべきではありません。
代わりにカスタムタイプを作成すべきです。
https://realm.github.io/SwiftLint/large_tuple.html
// bad
let foo: (Int, Int, Int)
// good
let foo: (Int, Int)
Leading Whitespace
ファイルは先頭にスペースを含んではいけません。
https://realm.github.io/SwiftLint/leading_whitespace.html
// bad
// foo
// good
// foo
Legacy CGGeometry Functions
構造体のエクステンションのプロパティとメソッドは、従来の関数より優先すべきです。
https://realm.github.io/SwiftLint/legacy_cggeometry_functions.html
// bad
CGRectGetWidth(rect)
CGRectGetHeight(rect)
CGRectGetMinX(rect)
CGRectGetMidX(rect)
CGRectGetMaxX(rect)
CGRectGetMinY(rect)
CGRectGetMidY(rect)
CGRectGetMaxY(rect)
CGRectIsNull(rect)
CGRectIsEmpty(rect)
CGRectIsInfinite(rect)
CGRectStandardize(rect)
CGRectIntegral(rect)
CGRectInset(rect, 10, 5)
CGRectOffset(rect, -2, 8.3)
CGRectUnion(rect1, rect2)
CGRectIntersection(rect1, rect2)
CGRectContainsRect(rect1, rect2)
CGRectContainsPoint(rect, point)
CGRectIntersectsRect(rect1, rect2)
// good
rect.width
rect.height
rect.minX
rect.midX
rect.maxX
rect.minY
rect.midY
rect.maxY
rect.isNull
rect.isEmpty
rect.isInfinite
rect.standardized
rect.integral
rect.insetBy(dx: 5.0, dy: -7.0)
rect.offsetBy(dx: 5.0, dy: -7.0)
rect1.union(rect2)
rect1.intersect(rect2)
rect1.contains(rect2)
rect.contains(point)
rect1.intersects(rect2)
Legacy Constant
構造スコープ定数は従来のグローバル定数より優先すべきです。
https://realm.github.io/SwiftLint/legacy_constant.html
// bad
CGRectInfinite
CGPointZero
CGRectZero
CGSizeZero
NSZeroPoint
NSZeroRect
NSZeroSize
CGRectNull
CGFloat(M_PI)
Float(M_PI)
// good
CGRect.infinite
CGPoint.zero
CGRect.zero
CGSize.zero
NSPoint.zero
NSRect.zero
NSSize.zero
CGRect.null
CGFloat.pi
Float.pi
Legacy Constructor
Swiftのコンストラクタは従来のコンビニエンス関数より優先すべきです。
https://realm.github.io/SwiftLint/legacy_constructor.html
// bad
CGPointMake(10, 10)
CGPointMake(xVal, yVal)
CGPointMake(calculateX(), 10)
CGSizeMake(10, 10)
CGSizeMake(aWidth, aHeight)
CGRectMake(0, 0, 10, 10)
CGRectMake(xVal, yVal, width, height)
CGVectorMake(10, 10)
CGVectorMake(deltaX, deltaY)
NSMakePoint(10, 10)
NSMakePoint(xVal, yVal)
NSMakeSize(10, 10)
NSMakeSize(aWidth, aHeight)
NSMakeRect(0, 0, 10, 10)
NSMakeRect(xVal, yVal, width, height)
NSMakeRange(10, 1)
NSMakeRange(loc, len)
UIEdgeInsetsMake(0, 0, 10, 10)
UIEdgeInsetsMake(top, left, bottom, right)
NSEdgeInsetsMake(0, 0, 10, 10)
NSEdgeInsetsMake(top, left, bottom, right)
CGVectorMake(10, 10)
NSMakeRange(10, 1)
UIOffsetMake(0, 10)
UIOffsetMake(horizontal, vertical)
// good
CGPoint(x: 10, y: 10)
CGPoint(x: xValue, y: yValue)
CGSize(width: 10, height: 10)
CGSize(width: aWidth, height: aHeight)
CGRect(x: 0, y: 0, width: 10, height: 10)
CGRect(x: xVal, y: yVal, width: aWidth, height: aHeight)
CGVector(dx: 10, dy: 10)
CGVector(dx: deltaX, dy: deltaY)
NSPoint(x: 10, y: 10)
NSPoint(x: xValue, y: yValue)
NSSize(width: 10, height: 10)
NSSize(width: aWidth, height: aHeight)
NSRect(x: 0, y: 0, width: 10, height: 10)
NSRect(x: xVal, y: yVal, width: aWidth, height: aHeight)
NSRange(location: 10, length: 1)
NSRange(location: loc, length: len)
UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 10)
UIEdgeInsets(top: aTop, left: aLeft, bottom: aBottom, right: aRight)
NSEdgeInsets(top: 0, left: 0, bottom: 10, right: 10)
NSEdgeInsets(top: aTop, left: aLeft, bottom: aBottom, right: aRight)
UIOffset(horizontal: 0, vertical: 10)
UIOffset(horizontal: horizontal, vertical: vertical)
Legacy Hashing
hashValue
をオーバーライドするのではなく、 hash(info:)
関数を使うべきです。
https://realm.github.io/SwiftLint/legacy_hashing.html
// bad
struct Foo: Hashable {
let bar: Int = 10
public var hashValue: Int {
return bar
}
}
// good
struct Foo: Hashable {
let bar: Int = 10
func hash(into hasher: inout Hasher) {
hasher.combine(bar)
}
}
Legacy NSGeometry Functions
従来の関数より構造体のエクステンションのプロパティとメソッドを使うべきです。
https://realm.github.io/SwiftLint/legacy_nsgeometry_functions.html
// bad
NSWidth(rect)
NSHeight(rect)
NSMinX(rect)
NSMidX(rect)
NSMaxX(rect)
NSMinY(rect)
NSMidY(rect)
NSMaxY(rect)
NSEqualRects(rect1, rect2)
NSEqualSizes(size1, size2)
NSEqualPoints(point1, point2)
NSEdgeInsetsEqual(insets2, insets2)
NSIsEmptyRect(rect)
NSIntegralRect(rect)
NSInsetRect(rect, 10, 5)
NSOffsetRect(rect, -2, 8.3)
NSUnionRect(rect1, rect2)
NSIntersectionRect(rect1, rect2)
NSContainsRect(rect1, rect2)
NSPointInRect(rect, point)
NSIntersectsRect(rect1, rect2)
// good
rect.width
rect.height
rect.minX
rect.midX
rect.maxX
rect.minY
rect.midY
rect.maxY
rect.isEmpty
rect.integral
rect.insetBy(dx: 5.0, dy: -7.0)
rect.offsetBy(dx: 5.0, dy: -7.0)
rect1.union(rect2)
rect1.intersect(rect2)
rect1.contains(rect2)
rect.contains(point)
rect1.intersects(rect2)
Line Length
1行にはあまりにも多くの文字を含めるべきではありません。
https://realm.github.io/SwiftLint/line_length.html
Mark
MARK
コメントは有効な形式であるべきです。
https://realm.github.io/SwiftLint/mark
// bad
//MARK: bad
// MARK:bad
// MARK: -bad
// MARK:- bad
// MARK bad
// good
// MARK: good
// MARK: - good
// MARK: -
Multiple Closures with Trailing Closure
複数のクロージャを引数とする場合、トレイリングクロージャを使うべきではありません。
https://realm.github.io/SwiftLint/multiple_closures_with_trailing_closure.html
// bad
foo.something(param1: { $0 }) { $0 + 1 }
// good
foo.something(param1: { $0 }, param2: { $0 + 1 })
Nesting
型は最大1レベル、ステートメントは最大5レベルの深さでネストすべきです。
https://realm.github.io/SwiftLint/nesting
// bad
class A { class B { class C { } } }
// good
class A { class B { } }
No Fallthrough Only
case
に少なくとも1つのステートメントが含まれている場合のみ、fallthrouth
を使うべきです。
https://realm.github.io/SwiftLint/no_fallthrough_only.html
// bad
switch myvar {
case 1:
fallthrough
case 2:
var a = 2
}
// good
switch myvar {
case 1:
var a = 1
fallthrough
case 2:
var a = 2
}
switch myvar {
case 1, 2:
var a = 2
}
Notification Center Detachment
オブジェクトは deinit
でのみ自分自身のオブザーバを削除すべきです。
https://realm.github.io/SwiftLint/notification_center_detachment.html
// bad
class Foo {
func bar() {
NotificationCenter.default.removeObserver(self)
}
}
// good
class Foo {
deinit {
NotificationCenter.default.removeObserver(self)
}
}
Opening Brace Spacing
{
は定義と同じ行で前に1つの半角スペースを置くべきです。
https://realm.github.io/SwiftLint/opening_brace_spacing.html
// bad
func abc(){
}
func abc()
{
}
// good
func abc() {
}
Operator Function Whitespace
演算子の定義時、1つの半角スペースで囲まれるべきです。
https://realm.github.io/SwiftLint/operator_function_whitespace.html
// bad
func <|(lhs: Int, rhs: Int) -> Int { }
func <| (lhs: Int, rhs: Int) -> Int { }
// good
func <| (lhs: Int, rhs: Int) -> Int { }
Private over fileprivate
fileprivate
より private
を使うべきです。
https://realm.github.io/SwiftLint/private_over_fileprivate.html
// TODO: 例を見ても法則がわからない。。
Private Unit Test
private
の単体テストは暗黙のうちにスキップされます。
https://realm.github.io/SwiftLint/private_unit_test.html
// bad
private class FooTests: XCTestCase {
func test1() { }
}
class FooTests: XCTestCase {
// bad
private func test1() { }
// good
func test1() { }
}
Protocol Property Accessors Order
プロトコルでプロパティを定義するときは、アクセサの順番を「ゲッター→セッター」とすべきです。
https://realm.github.io/SwiftLint/prohibited_calls_to_super.html
protocol Foo {
// bad
var bar: String { set get }
// good
var bar: String { set }
var bar: String { get }
var bar: String { get set }
}
Redundant Discardable Let
関数の戻り値を使わずに実行する場合、 let _ = foo()
より _ = foo()
を使うべきです。
https://realm.github.io/SwiftLint/redundant_discardable_let.html
// bad
let _ = foo()
if let _ = foo() { }
guard let _ = foo() else { return }
// good
_ = foo()
Redundant @objc Attribute
冗長な @objc
属性は避けるべきです。
https://realm.github.io/SwiftLint/redundant_objc_attribute.html
// bad
@objc @IBAction private func foo(_ sender: Any) { }
// good
@IBAction private func foo(_ sender: Any) { }
Redundant Optional Initialization
オプショナル型の変数を nil
で初期化するのは冗長です。
https://realm.github.io/SwiftLint/redundant_optional_initialization.html
// bad
var myVar: Int? = nil
// good
var myVar: Int?
let myVar: Int? = nil
var myVar: Int? = 0
Redundant Set Access Control Rule
プロパティのセッターのアクセスレベルは、変数のアクセスレベルと同様であれば明示的に指定すべきではありません。
https://realm.github.io/SwiftLint/redundant_set_access_control_rule.html
// bad
private(set) private var foo: Int
// good
private(set) public var foo: Int
Redundant String Enum Value
文字列の列挙型の値は、ケースと同名なら省略できます。
https://realm.github.io/SwiftLint/redundant_string_enum_value.html
// bad
enum Numbers: String {
case one = "one"
case two = "two"
}
// good
enum Numbers: String {
case one
case two
}
enum Numbers: String {
case one = "ONE"
case two = "TWO"
}
Redundant Void Return
関数の定義で Void
を返すのは冗長です。
https://realm.github.io/SwiftLint/redundant_void_return.html
// bad
func foo() -> Void { }
func foo() -> () { }
// good
func foo() { }
let foo: Int -> Void
Returning Whitespace
戻り値の矢印と型は1つの半角スペースまたは別の行で区切るべきです。
https://realm.github.io/SwiftLint/returning_whitespace.html
// bad
func abc()-> Int { }
func abc() ->Int { }
func abc()->Int { }
// good
func abc() -> Int { }
func abc()
-> Int { }
func abc() ->
Int { }
Shorthand Operator
省略形の演算子を使うべきです。
https://realm.github.io/SwiftLint/shorthand_operator.html
// bad
foo = foo + 1
foo = foo - 1
foo = foo * 1
foo = foo / 1
// good
foo += 1
foo -= 1
foo *= 1
foo /= 1
Statement Position
else
と catch
は、前の定義の1つの半角スペースの後ろで同じ行にあるべきです。
https://realm.github.io/SwiftLint/statement_position.html
// bad
}else {
}
catch {
// good
} else {
} catch {
Superfluous Disable Command
無効化されたルールが無効化された領域で違反を起こさなかった場合、SwiftLintの disable
コマンドは不要です。
https://realm.github.io/SwiftLint/superfluous_disable_command.html
Switch and Case Statement Alignment
case
文はそれを囲む switch
文と同じインデントにすべきです。
https://realm.github.io/SwiftLint/switch_and_case_statement_alignment.html
// bad
switch someBool {
case true:
print("red")
case false:
print("blue")
}
// good
switch someBool {
case true:
print("red")
case false:
print("blue")
}
Syntactic Sugar
糖衣構文を使うべきです。
https://realm.github.io/SwiftLint/syntactic_sugar.html
// bad
let x: Array<String>
let x: Dictionary<Int, String>
let x: Optional<Int>
let x: ImplicitlyUnwrappedOptional<Int>
// good
let x: [String]
let x: [Int: String]
let x: Int?
let x: Int!
Todo
TODO
と FIXME
は解決すべきです。
https://realm.github.io/SwiftLint/todo
// bad
// TODO:
// FIXME:
Trailing Comma
配列やディクショナリの末尾のカンマは避けるべきです。
https://realm.github.io/SwiftLint/trailing_comma.html
// bad
let array = [1, 2, 3,]
let dictionary = ["foo": 1, "bar": 2,]
// good
let array = [1, 2, 3]
let dictionary = ["foo": 1, "bar": 2]
Trailing Newline
ファイルは末尾に1つの改行を持つべきです。
https://realm.github.io/SwiftLint/trailing_newline.html
Trailing Semicolon
行の末尾にセミコロンを付けるべきではありません。
https://realm.github.io/SwiftLint/trailing_semicolon.html
// bad
let a = 0;
// good
let a = 0
Trailing Whitespace
行の末尾に半角スペースを付けるべきではありません。
https://realm.github.io/SwiftLint/trailing_whitespace.html
// bad
let a = 1
// good
let a = 1
Type Body Length
型内はあまりにも多くの行にまたがるべきではないです。
https://realm.github.io/SwiftLint/type_body_length.html
Type Name
型名は英数のみを含み、大文字で始まり、3〜40文字にすべきです。
https://realm.github.io/SwiftLint/type_name.html
// bad
class My_Type { }
class myType { }
class aa { }
// good
class MyType { }
Unneeded Break in Switch
不要な break
は避けるべきです。
https://realm.github.io/SwiftLint/unneeded_break_in_switch.html
switch a {
// bad
case .foo:
something()
break
// good
case .bar:
something()
case .baz:
break
case .qux:
for i in [0, 1, 2] { break }
}
Unused Closure Parameter
クロージャで使われていないパラメータは _
に置き換えるべきです。
https://realm.github.io/SwiftLint/unused_closure_parameter.html
// bad
[1, 2].map { number in
3
}
// good
[1, 2].map { _ in
3
}
[1, 2].map { number in
number + 1
}
[1, 2].map { $0 + 1 }
Unused Control Flow Label
未使用の制御フローラベルは削除すべきです。
https://realm.github.io/SwiftLint/unused_control_flow_label.html
// bad
loop: while true { break }
// good
loop: while true { break loop }
loop: while true { continue loop }
Unused Enumerated
インデックスまたはアイテムが使われていない場合、 .enumerated()
を削除できます。
https://realm.github.io/SwiftLint/unused_enumerated.html
// TODO: わからない。。
Unused Optional Binding
let _ =
より != nil
を使うべきです。
https://realm.github.io/SwiftLint/unused_optional_binding.html
// bad
if let _ = a { }
// good
if a != nil { }
Unused Setter Value
セッターの値は使われるべきです。
https://realm.github.io/SwiftLint/unused_setter_value.html
var aValue: String {
get {
return Persister.shared.aValue
}
set {
// bad
Persister.shared.aValue = aValue
// good
Persister.shared.aValue = newValue
}
// bad
set { }
}
Valid IBInspectable
@IBInspectable
はサポートされている型の変数のみに使い、その型を明示的にすべきです。
https://realm.github.io/SwiftLint/valid_ibinspectable.html
class Foo {
// bad
@IBInspectable private let count: Int
@IBInspectable private var count = 0
@IBInspectable private var count: Int?
@IBInspectable private var count: Int!
// good
@IBInspectable private var count: Int
@IBInspectable private var count: Int = 0
}
Vertical Parameter Alignment
関数の定義時、パラメータが複数行にまたがっている場合は垂直方向に揃えるべきです。
https://realm.github.io/SwiftLint/vertical_parameter_alignment.html
// bad
func validateFunction(_ file: File, kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) { }
func validateFunction(_ file: File, kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) { }
// good
func validateFunction(_ file: File, kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) { }
Vertical Whitespace
空白行は1行に制限します。
https://realm.github.io/SwiftLint/vertical_whitespace.html
Void Return
-> ()
より -> Void
を使うべきです。
https://realm.github.io/SwiftLint/void_return.html
// bad
let abc: () -> () = { }
// good
let abc: () -> Void = { }
Weak Computed Property
コンピューテッドプロパティに weak
を追加しても効果はありません。
https://realm.github.io/SwiftLint/weak_computed_property.html
class Foo {
private weak var _delegate: SomeProtocol?
// bad
weak var delegate: SomeProtocol? {
// good
var delegate: SomeProtocol? {
get { return _delegate }
set { _delegate = newValue }
}
}
Weak Delegate
デリゲートは循環参照を避けるために弱参照とすべきです。
https://realm.github.io/SwiftLint/weak_delegate.html
class Foo {
// bad
var delegate: SomeProtocol?
// good
weak var delegate: SomeProtocol?
}
XCTFail Message
XCTFail
の呼び出しにはアサーションの説明を含めるべきです。
https://realm.github.io/SwiftLint/xctfail_message.html
func testFoo() {
// bad
XCTFail()
// good
XCTFail("bar")
}
Opt-in
デフォルトで無効になっているルールの一覧です。
AnyObject Protocol
クラス専用のプロトコルでは、 class
より AnyObject
を使うべきです。
https://realm.github.io/SwiftLint/anyobject_protocol.html
// bad
protocol SomeClassOnlyProtocol: class { }
// good
protocol SomeClassOnlyProtocol: AnyObject { }
Array Init
シーケンスを配列に変換する場合、 seq.map { $0 }
より Array(seq)
を使うべきです。
https://realm.github.io/SwiftLint/array_init.html
// bad
seq.map { $0 }
// good
Array(seq)
Attributes
属性は関数や型では別の行にあるべきですが、変数やインポートでは同じ行にあるべきです。
https://realm.github.io/SwiftLint/attributes
// bad
@available(iOS 9.0, *) func animate(view: UIStackView)
@available(iOS 9.0, *) class UIStackView
@objc
var x: String
@testable
import SourceKittenFramework
// good
@available(iOS 9.0, *)
func animate(view: UIStackView)
@available(iOS 9.0, *)
class UIStackView
@objc var x: String
@testable import SourceKittenFramework
Closure Body Length
クロージャ内はあまりにも多くの行にまたがるべきではないです。
https://realm.github.io/SwiftLint/closure_body_length.html
// bad
foo.bar { toto in
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
let a = 0
}
// good
foo.bar { $0 }
foo.bar { toto in
}
Closure End Indentation
クロージャの終了は開始と同様のインデントを持つべきです。
https://realm.github.io/SwiftLint/closure_end_indentation.html
// bad
SignalProducer(values: [1, 2, 3])
.startWithNext { number in
print(number)
}
// good
SignalProducer(values: [1, 2, 3])
.startWithNext { number in
print(number)
}
[1, 2].map { $0 + 1 }
Closure Spacing
クロージャ内は各括弧の内側に1つの半角スペースがあるべきです。
https://realm.github.io/SwiftLint/closure_spacing.html
// bad
[].filter {$0.contains(location)}
// good
[].filter { $0.contains(location) }
Collection Element Alignment
コレクション内の全要素は垂直方向に揃うべきです。
https://realm.github.io/SwiftLint/collection_element_alignment.html
// bad
let abc = [
"alpha": "a",
"beta": "b",
"gamma": "g",
"delta": "d",
"epsilon": "e"
]
// good
let abc = [
"alpha": "a",
"beta": "b",
"gamma": "g",
"delta": "d",
"epsilon": "e"
]
let abc = [1, 2, 3, 4]
let abc = [
1, 2, 3, 4
]
Conditional Returns on Newline
条件文では次の行でリターンすべきです。
https://realm.github.io/SwiftLint/conditional_returns_on_newline.html
// bad
guard true else { return }
// good
guard true else {
return true
}
Contains over first not nil
first(where:) != nil
より contains
を使うべきです。
https://realm.github.io/SwiftLint/contains_over_first_not_nil.html
// bad
myList.first { $0 % 2 == 0 } != nil
myList.first(where: { $0 % 2 == 0 }) != nil
// good
myList.contains { $0 % 2 == 0 }
myList.contains(where: { $0 % 2 == 0 })
Convenience Type
静的メンバーのみをホストするために使われる型は、インスタンス化を回避するために、case
のない列挙型として実装すべきです。
https://realm.github.io/SwiftLint/convenience_type.html
// bad
struct Math {
public static let pi = 3.14
}
class Math {
public static let pi = 3.14
}
// good
enum Math {
public static let pi = 3.14
}
// 継承を伴う場合はOK
class MathViewController: UIViewController {
public static let pi = 3.14
}
// Obj-Cに見えるクラスはOK
@objc class Math: NSObject {
public static let pi = 3.14
}
// 静的でない型もある場合はOK
struct Math {
public static let pi = 3.14
public let randomNumber = 2
}
Discouraged Object Literal
オブジェクトリテラルよりイニシャライザを使うべきです。
https://realm.github.io/SwiftLint/discouraged_object_literal.html
// bad
let image = #imageLiteral(resourceName: "image.jpg")
let color = #colorLiteral(red: value, green: value, blue: value, alpha: 1)
// good
let image = UIImage(named: "image")
let color = UIColor(red: value, green: value, blue: value, alpha: 1)
Discouraged Optional Boolean
オプショナル型よりそうでない Bool
型を使うべきです。
https://realm.github.io/SwiftLint/discouraged_optional_boolean.html
// bad
var foo: Bool?
// good
var foo: Bool
Discouraged Optional Collection
オプショナルのコレクションより空のコレクションを使うべきです。
https://realm.github.io/SwiftLint/discouraged_optional_collection.html
// bad
var foo: [Int]?
var foo: [String: Int]?
let foo: [Int]? = nil
let foo: [String: Int]? = nil
// good
var foo: [Int]
var foo: [String: Int]
let foo: [Int] = []
let foo: [String: Int] = [:]
Empty Count
count
を 0
と比較するより isEmpty
を使うべきです。
https://realm.github.io/SwiftLint/empty_count.html
// bad
[Int]().count == 0
[Int]().count > 0
[Int]().count != 0
// good
[Int]().isEmpty
Empty String
空の文字列と比較するより isEmpty
を使うべきです。
https://realm.github.io/SwiftLint/empty_string.html
// bad
myString == ""
myString != ""
// good
myString.isEmpty
!myString.isEmpty
Empty XCTest Method
空のXCTestメソッドを実装すべきではありません。
https://realm.github.io/SwiftLint/empty_xctest_method.html
// bad
class TotoTests: XCTestCase {
override func setUp() {
}
override func tearDown() {
}
func testFoo() {
}
}
// good
class TotoTests: XCTestCase {
var foobar: Foobar?
override func setUp() {
super.setUp()
foobar = Foobar()
}
override func tearDown() {
foobar = nil
super.tearDown()
}
func testFoo() {
XCTAssertTrue(foobar?.foo)
}
func helperFunction() {
}
}
Explicit ACL
全ての定義はアクセス制御レベルのキーワードを明示的に指定すべきです。
https://realm.github.io/SwiftLint/explicit_acl.html
// bad
enum A { }
// good
internal enum A { }
Explicit Enum Raw Value
列挙型はローバリューを明示的に割り当てるべきです。
https://realm.github.io/SwiftLint/explicit_enum_raw_value.html
// bad
enum Numbers: Int {
case one
case two
}
// good
enum Numbers: Int {
case one = 1
case two = 2
}
Explicit Init
.init()
を明示的に呼び出すべきではありません。
https://realm.github.io/SwiftLint/explicit_init.html
// bad
[1].flatMap { String.init($0) }
[String.self].map { Type in Type.init(1) }
// good
[1].flatMap(String.init)
[String.self].map { $0.init(1) }
[String.self].map { type in type.init(1) }
Explicit Self
インスタンス変数と関数は self.
で明示的にアクセスされるべきです。
https://realm.github.io/SwiftLint/explicit_self.html
struct A {
let p1: Int
func f1() { }
func f2() {
// bad
f1()
_ = p1
// good
self.f1()
_ = self.p1
}
}
Explicit Top Level ACL
最上位の定義はアクセス制御レベルを明示的に指定すべきです。
https://realm.github.io/SwiftLint/explicit_top_level_acl.html
// bad
enum A {
enum B { }
}
// good
internal enum A {
enum B { }
}
Explicit Type Interface
プロパティは型インターフェースを持つべきです。
https://realm.github.io/SwiftLint/explicit_type_interface.html
class Foo {
// bad
var myVar = 0
// good
var myVar: Int? = 0
}
Extension Access Modifier
エクステンションにはアクセス修飾子を使うべきです。
https://realm.github.io/SwiftLint/explicit_type_interface.html
// bad
extension Foo {
public var bar: Int { return 1 }
public var baz: Int { return 1 }
}
// good
public extension Foo {
var bar: Int { return 1 }
var baz: Int { return 1 }
}
Fallthrough
fallthrough
は使うべきではありません。
https://realm.github.io/SwiftLint/fallthrough
// bad
switch foo {
case .bar:
fallthrough
case .bar2:
something()
}
// good
switch foo {
case .bar, .bar2:
something()
}
Fatal Error Message
fatalError
はメッセージを付けて呼び出すべきです。
https://realm.github.io/SwiftLint/fatal_error_message.html
// bad
func foo() {
fatalError()
}
// good
func foo() {
fatalError("Foo")
}
File Header
// TODO: 例を見ても法則がわからない。。
File Name
ファイル名はファイル内で定義されている型またはエクステンションと一致すべきです。
https://realm.github.io/SwiftLint/file_name.html
First Where
コレクションでは .filter {} .first
より .first(where:)
を使うべきです。
https://realm.github.io/SwiftLint/first_where.html
// bad
myList.filter { $0 % 2 == 0 } .first
// good
myList.first(where: { $0 % 2 == 0 })
myList.first { $0 % 2 == 0 }
Force Unwrapping
強制アンラップ( !
)は使うべきではありません。
https://realm.github.io/SwiftLint/force_unwrapping.html
// bad
let url = NSURL(string: query)!
// good
if let url = NSURL(string: query) { }
Function Default Parameter at End
関数でデフォルト値を持つ引数は後ろにまとめるべきです。
https://realm.github.io/SwiftLint/function_default_parameter_at_end.html
// bad
func foo(y: Int = 0, x: String, z: CGFloat = 0) { }
// good
func foo(x: String, y: Int = 0, z: CGFloat = 0) { }
Identical Operands
同一のオペランドを比較するのはおそらく間違いです。
https://realm.github.io/SwiftLint/identical_operands.html
// bad
foo == foo
// good
foo == bar
Implicit Return
クロージャでは暗黙のリターンを優先すべきです。
https://realm.github.io/SwiftLint/implicit_return.html
// bad
foo.map {
return $0 + 1
}
// good
foo.map { $0 + 1 }
Implicitly Unwrapped Optional
暗黙的にアンラップされるオプショナル型はできる限り使うべきではありません。
https://realm.github.io/SwiftLint/implicitly_unwrapped_optional.html
// bad
private var label: UILabel!
let int: Int! = 42
// good
@IBOutlet private var label: UILabel!
let int: Int? = 42
Joined Default Parameter
デフォルトの区切り文字は明示的に使うべきではありません。
https://realm.github.io/SwiftLint/joined_default_parameter.html
// bad
let foo = bar.joined(separator: "")
// good
let foo = bar.joined()
let foo = bar.joined(separator: ",")
Last Where
コレクションでは .filter {} .last
より .last(where:)
を使うべきです。
https://realm.github.io/SwiftLint/last_where.html
// bad
myList.filter { $0 % 2 == 0 } .last
// good
myList.last(where: { $0 % 2 == 0 })
Legacy Random
従来の関数より type.ramdom(in:)
を使うべきです。
https://realm.github.io/SwiftLint/legacy_random.html
// bad
arc4random(10)
arc4random_uniform(83)
drand48(52)
// good
Int.random(in: 0..<10)
Double.random(in: 8.6...111.34)
Float.random(in: 0..<1)
Variable Declaration Whitespace
let
と var
は他のステートメントと空白行で区切るべきです。
https://realm.github.io/SwiftLint/variable_declaration_whitespace.html
// bad
let a = 0
var x = 1
x = 2
// good
let a = 0
var x = 1
x = 2
Literal Expression End Indentation
配列とディクショナリのリテラルの末尾は、開始行と同様のインデントを持つべきです。
https://realm.github.io/SwiftLint/literal_expression_end_indentation.html
// bad
let x = [
1,
2
]
// good
[1, 2, 3]
let x = [
1,
2
]
let x = [1,
2
]
let x = [
1,
2]
Lower ACL than parent
定義が親よりも低いまたは同じアクセス制御レベルを持つようにすべきです。
https://realm.github.io/SwiftLint/lower_acl_than_parent.html
// bad
struct Foo {
public func bar() { }
}
// good
public struct Foo {
public func bar() { }
}
Missing Docs
定義はドキュメント化すべきです。
https://realm.github.io/SwiftLint/missing_docs.html
// good
/// docs
public class A {
/// docs
public func b() { }
}
/// docs
public class B: A {
// オーバーライドメソッドはOK
override public func b() { }
}
Modifier Order
修飾子の順番は一貫しているべきです。
https://realm.github.io/SwiftLint/modifier_order.html
public class Foo {
// bad
convenience required public init() { }
static public let bar = 42
// good
public convenience required init() { }
public static let bar = 42
}
Multiline Arguments
引数は同じ行に入れるか1行に1つずつ入れるべきです。
https://realm.github.io/SwiftLint/multiline_arguments.html
// bad
func foo(
param1: "Param1", param2: "Param2",
param3: "Param3"
)
// good
func foo(param1: "Param1", param2: "Param2", param3: "Param3")
func foo(
param1: "Param1",
param2: "Param2",
param3: "Param3"
)
Multiline Arguments Brackets
複数行の引数は、それらを括る大括弧を新しい行に持つべきです。
https://realm.github.io/SwiftLint/multiline_arguments_brackets.html
// bad
foo(param1: "Param1",
param2: "Param2"
)
foo(
param1: "Param1",
param2: "Param2")
// good
foo(param1: "Param1", param2: "Param2")
foo(
param1: "Param1",
param2: "Param2"
)
Multiline Function Chains
関数を連鎖的に呼び出す場合、同じ行に入れるか1行に1つずつ入れるべきです。
https://realm.github.io/SwiftLint/multiline_function_chains.html
// bad
let evenSquaresSum = [20, 17, 35, 4]
.filter { $0 % 2 == 0 } .map { $0 * $0 }
.reduce(0, +)
// good
let evenSquaresSum = [20, 17, 35, 4].filter { $0 % 2 == 0 } .map { $0 * $0 } .reduce(0, +)
let evenSquaresSum = [20, 17, 35, 4]
.filter { $0 % 2 == 0 }
.map { $0 * $0 }
.reduce(0, +)
Multiline Literal Brackets
複数行のリテラルは、新しい行にそれを括る大括弧を入れるべきです。
https://realm.github.io/SwiftLint/multiline_literal_brackets.html
// bad
let trio = ["harry",
"ronald",
"hermione"
]
let trio = [
"harry",
"ronald",
"hermione"]
// good
let trio = ["harry", "ronald", "hermione"]
let trio = [
"harry",
"ronald",
"hermione"
]
Multiline Parameters
関数とメソッドの引数は、同様の行にあるか1行に1つずつあるべきです。
https://realm.github.io/SwiftLint/multiline_parameters.html
// bad
func foo(param1: Int, param2: Bool,
param3: [String]) { }
// good
func foo(param1: Int, param2: Bool, param3: [String]) { }
func foo(param1: Int,
param2: Bool,
param3: [String]) { }
Multiline Parameters Brackets
複数行の引数は、新しい行にそれを括る大括弧を入れるべきです。
https://realm.github.io/SwiftLint/multiline_parameters_brackets.html
// bad
func foo(param1: "Param1",
param2: "Param2",
param3: "Param3"
)
func foo(
param1: "Param1",
param2: "Param2",
param3: "Param3")
// good
func foo(param1: "Param1", param2: "Param2", param3: "Param3")
func foo(
param1: "Param1",
param2: "Param2",
param3: "Param3"
)
Nimble Operator
フリーのmatcher関数よりNimble演算子のオーバーロードを使うべきです。
https://realm.github.io/SwiftLint/nimble_operator.html
//bad
expect(seagull.squawk).to(equal("Hi"))
expect(seagull.squawk).toNot(equal("Hi"))
expect(10).to(beGreaterThan(2))
// good
expect(seagull.squawk) == "Hi!"
expect(seagull.squawk) != "Hi!"
expect(10) > 2
No Extension Access Modifier
エクステンションにアクセス修飾子を付けるべきではありません。
https://realm.github.io/SwiftLint/no_extension_access_modifier.html
// bad
private extension String { }
fileprivate extension String { }
internal extension String { }
public extension String { }
open extension String { }
// good
extension String { }
No Grouping Extension
エクステンションは同じソースファイル内のコードをグループ化するために使うべきではありません。
https://realm.github.io/SwiftLint/no_grouping_extension.html
// bad
enum Fruit { }
extension Fruit { }
// good
// プロトコルのデフォルト実装はOK
protocol Food { }
extension Food { }
NSLocalizedString Key
genstringsが機能するためには、静的文字列を NSLocalizedString
のキーとして使うべきです。
https://realm.github.io/SwiftLint/nslocalizedstring_key.html
// bad
NSLocalizedString(method(), comment: nil)
// good
NSLocalizedString("key", comment: nil)
Number Separator
_
は十進数で千の区切り文字として使うべきです。
// bad
let foo = 1000
let foo = 1000_000.000_000_1
let foo = 1_000_000.000000_1
let foo = 1_0_00_000.000_000_1
// good
let foo = 1_000
let foo = 1_000_000.000_000_1
Object Literal
画像や色はイニシャライザよりリテラルを使って生成すべきです。
https://realm.github.io/SwiftLint/object_literal.html
// bad
let image = UIImage(named: "image")
let color = UIColor(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1.0)
// good
let image = #imageLiteral(resourceName: "image.jpg")
let color = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1.0)
Operator Usage Whitespace
演算子を使うときは1つの半角スペースで囲まれるべきです。
https://realm.github.io/SwiftLint/operator_usage_whitespace.html
// bad
let foo = 1+2
let foo=1+2
// good
let foo = 1 + 2
Overridden methods call super
一部のオーバーライドメソッドは常に親クラスのメソッドを呼び出すべきです。
https://realm.github.io/SwiftLint/overridden_methods_call_super.html
// bad
class VC: UIViewController {
override func viewWillAppear(_ animated: Bool) {
}
}
// good
class VC: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func loadView() {
}
}
Override in Extension
エクステンションでは定義をオーバーライドすべきではありません。
https://realm.github.io/SwiftLint/override_in_extension.html
extension Person {
// good
var age: Int { return 42 }
func celebrateBirthday() { }
// bad
override var age: Int { return 42 }
override func celebrateBirthday() { }
}
Pattern Matching Keywords
キーワードをタプルの外に出し、複数のパターンマッチングバインディングを組み合わせるべきです。
https://realm.github.io/SwiftLint/pattern_matching_keywords.html
switch foo {
// bad
case (let x, let y):
// good
case let (x, y):
}
Prefixed Top-Level Constant
最上位の定数はプリフィックスに k
を付けるべきです。
https://realm.github.io/SwiftLint/prefixed_top_level_constant.html
// bad
let bar = 20.0
// good
let kBar = 20.0
struct Foo {
let bar = 20.0
}
Private Actions
@IBAction
は private
にすべきです。
https://realm.github.io/SwiftLint/private_actions.html
// bad
class Foo {
@IBAction func barButtonTapped(_ sender: UIButton) { }
}
// good
class Foo {
@IBAction private func barButtonTapped(_ sender: UIButton) { }
}
Private Outlets
@IBOutlet
は private
にすべきです。
∵上位レイヤーへ UIKit
が漏洩するのを防ぐため
https://realm.github.io/SwiftLint/private_outlets.html
// bad
class Foo {
@IBOutlet var label: UILabel?
}
// good
class Foo {
@IBOutlet private var label: UILabel?
}
Prohibited Interface Builder
IBを使ってビューを生成するのは避けるべきです。
https://realm.github.io/SwiftLint/prohibited_interface_builder.html
class ViewController: UIViewController {
// bad
@IBOutlet var label: UILabel!
@IBAction func buttonTapped(_ sender: UIButton) { }
// good
var label: UILabel!
@objc func buttonTapped(_ sender: UIButton) { }
}
Prohibited calls to super
一部のメソッドは親クラスのメソッドを呼び出してはいけません。
https://realm.github.io/SwiftLint/prohibited_calls_to_super.html
// bad
class VC: UIViewController {
override func loadView() {
super.loadView()
}
}
Quick Discouraged Call
describe
や context
内で処理を呼び出すべきではありません。
https://realm.github.io/SwiftLint/quick_discouraged_call.html
class TotoTests: QuickSpec {
override func spec() {
describe("foo") {
// bad
let foo = Foo()
context("foo") {
// bad
foo.bar()
it("does something") {
// good
let foo = Foo()
foo.bar()
}
}
}
}
}
Quick Discouraged Focused Test
一部のみ有効となるテストは実行すべきではありません。
https://realm.github.io/SwiftLint/quick_discouraged_focused_test.html
class TotoTests: QuickSpec {
override func spec() {
// bad
fdescribe("foo") { }
fcontext("foo") { }
fit("foo") { }
fitBehavesLike("foo")
// good
describe("foo") { }
context("foo") { }
it("foo") { }
itBehavesLike("foo")
}
}
Quick Discouraged Pending Test
一部のみ無効となるテストは実行すべきではありません。
https://realm.github.io/SwiftLint/quick_discouraged_pending_test.html
class TotoTests: QuickSpec {
override func spec() {
// bad
xdescribe("foo") { }
xcontext("foo") { }
xit("foo") { }
pending("foo")
xitBehavesLike("foo")
// good
describe("foo") { }
context("foo") { }
it("foo") { }
itBehavesLike("foo")
}
}
Redundant Nil Coalescing
??
演算子は左辺が nil
の場合のみ評価されるため、右辺に nil
を記述するのは冗長です。
https://realm.github.io/SwiftLint/redundant_nil_coalescing.html
// bad
var myVar: Int? = nil
myVar ?? nil
// good
var myVar: Int?
myVar ?? 0
Redundant Type Annotation
変数は冗長な型アノテーションを持つべきではありません。
https://realm.github.io/SwiftLint/redundant_type_annotation.html
// bad
var url: URL = URL()
// good
var url = URL()
var url: CustomStringConvertible = URL()
Required Deinit
クラスは明示的な deinit
メソッドを持つべきです。
https://realm.github.io/SwiftLint/required_deinit.html
// bad
class Apple { }
// good
class Apple {
deinit { }
}
Required Enum Case
特定のプロトコルに準拠した列挙型は特定のケースを実装する必要があります。
https://realm.github.io/SwiftLint/required_enum_case.html
// bad
enum MyNetworkResponse: String, NetworkResponsable {
case success
case error
}
// good
enum MyNetworkResponse: String, NetworkResponsable {
case success
case error
case notConnected
}
enum MyNetworkResponse: String, NetworkResponsable {
case success
case error
case notConnected(error: Error)
}
Single Test Class
テストファイルは単一の QuickSpec
または XCTestCase
クラスを含むべきです。
https://realm.github.io/SwiftLint/single_test_class.html
// bad
class FooTests: QuickSpec { }
class BarTests: QuickSpec { }
class FooTests: XCTestCase { }
class BarTests: XCTestCase { }
class FooTests: XCTestCase { }
class BarTests: QuickSpec { }
// good
class FooTests: XCTestCase { }
class FooTests: QuickSpec { }
Min or Max over Sorted First or Last
sorted().first
や sorted().last
より min()
や max()
を使うべきです。
https://realm.github.io/SwiftLint/min-or-max-over-sorted-first-or-last
// bad
myList.sorted().first
myList.sorted().last
let min = myList.sorted(by: >).first
// good
myList.min()
myList.max()
let min = myList.min(by: >)
Sorted Imports
インポート文はソートされるべきです。
https://realm.github.io/SwiftLint/sorted_imports.html
// bad
import AAA
import CCC
import BBB
import DDD
// good
import AAA
import BBB
import CCC
import DDD
Static Operator
演算子は自由関数でなく静的関数として定義すべきです。
https://realm.github.io/SwiftLint/static_operator.html
// bad
func == (lhs: A, rhs: A) -> Bool {
return false
}
func == <T>(lhs: A<T>, rhs: A<T>) -> Bool {
return false
}
// good
class A: Equatable {
static func == (lhs: A, rhs: A) -> Bool {
return false
}
}
class A<T>: Equatable {
static func == <T>(lhs: A<T>, rhs: A<T>) -> Bool {
return false
}
}
Strict fileprivate
fileprivate
は避けるべきです。
https://realm.github.io/SwiftLint/strict_fileprivate.html
// bad
fileprivate extension String { }
extension String {
fileprivate func Something() { }
}
// good
private extension String { }
extension String {
func Something() { }
}
Strong IBOutlet
@IBOutlet
は弱参照で定義すべきではありません。
https://realm.github.io/SwiftLint/strong_iboutlet.html
// bad
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel?
@IBOutlet unowned var label: UILabel!
}
// good
class ViewController: UIViewController {
@IBOutlet var label: UILabel?
weak var label: UILabel!
}
Switch Case on Newline
switch
文の中の case
文は常に改行すべきです。
https://realm.github.io/SwiftLint/switch_case_on_newline.html
// bad
switch foo {
case 1: return true
}
// good
switch foo {
case 1:
return true
}
Toggle Bool
someBool = !someBool
より someBool.toggle()
を使うべきです。
https://realm.github.io/SwiftLint/toggle_bool.html
// bad
isHidden = !isHidden
// good
isHidden.toggle()
Trailing Closure
できる限りトレイリングクロージャを使うべきです。
https://realm.github.io/SwiftLint/trailing_closure.html
// bad
foo.map({ $0 + 1 })
foo.reduce(0, combine: { $0 + 1 })
// good
foo.map { $0 + 1 }
foo.reduce(0) { $0 + 1 }
Unavailable Function
未実装の関数は使用不可としてマークされるべきです。
https://realm.github.io/SwiftLint/unavailable_function.html
// bad
class ViewController: UIViewController {
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// good
class ViewController: UIViewController {
@available(*, unavailable)
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Unneeded Parentheses in Closure Argument
クロージャ引数の定義時に括弧は不要です。
https://realm.github.io/SwiftLint/unneeded_parentheses_in_closure_argument.html
// bad
let foo = { (bar) in }
let foo = { (bar, _) in }
// good
let foo = { (bar: Int) in }
let foo = { bar in }
let foo = { bar, _ in }
Untyped Error in Catch
catch
文は型キャストなしでエラー変数を定義すべきではありません。
https://realm.github.io/SwiftLint/untyped_error_in_catch.html
// bad
do {
try foo()
} catch let error {
}
// good
do {
try foo()
} catch let error as MyError {
} catch { }
Unused Import
インポートされた全てのモジュールがファイルをコンパイルするために必要とされるべきです。
https://realm.github.io/SwiftLint/unused_import.html
// bad
import Foundation
class A { }
// good
import Foundation
@objc
class A { }
Unused Private Declaration
private
の定義はそのファイル内で参照されるべきです。
https://realm.github.io/SwiftLint/unused_private_declaration.html
// bad
private let a = 0
// good
private let a = 0
_ = a
Vertical Parameter Alignment On Call
関数の呼び出し時、パラメータが複数行にまたがっている場合は垂直方向に揃えるべきです。
https://realm.github.io/SwiftLint/vertical_parameter_alignment_on_call.html
// bad
validateFunction(_ file: File, kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) { }
validateFunction(_ file: File, kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) { }
// good
validateFunction(_ file: File, kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) { }
Vertical Whitespace Between Cases
SwitchのCase間は空白行を1行含んでください。
https://realm.github.io/SwiftLint/vertical_whitespace_between_cases.html
// bad
switch x {
case .valid:
print("x is valid")
case .invalid:
print("x is invalid")
}
// good
switch x {
case .valid:
print("x is valid")
case .invalid:
print("x is invalid")
}
Vertical Whitespace before Closing Braces
中括弧を閉じる前に空白行を入れないでください。
https://realm.github.io/SwiftLint/vertical_whitespace_before_closing_braces.html
// bad
{
{
}
}
// good
{
{
}
}
Vertical Whitespace after Opening Braces
中括弧を開いた後に空白行を入れないでください。
https://realm.github.io/SwiftLint/vertical_whitespace_after_opening_braces.html
// bad
{
{
}
}
// good
{
{
}
}
XCTest Specific Matcher
XCTAssertEqual
や XCTAssertNotEqual
より特定のXCTestマッチャーを使うべきです。
https://realm.github.io/SwiftLint/xctest_specific_matcher.html
// bad
XCTAssertEqual(foo, true)
XCTAssertEqual(foo, false)
XCTAssertEqual(foo, nil)
XCTAssertNotEqual(foo, true)
XCTAssertNotEqual(foo, false)
XCTAssertNotEqual(foo, nil)
// good
XCTAssertFalse(foo)
XCTAssertTrue(foo)
XCTAssertNil(foo)
XCTAssertNotNil(foo)
XCTAssertEqual(foo, 2)
Yoda condition rule
変数は比較演算子の左側、定数は右側に配置すべきです。
https://realm.github.io/SwiftLint/yoda_condition_rule.html
// bad
if 42 == foo { }
// good
if foo == 42 { }
おわりに
SwiftLintのルールを一通り眺めるだけでもSwiftyに書けるようになった気がします。
ただ、これらを他のメンバーにも守ってもらうには、やはりSwiftLintの導入が便利です。