SwiftLintのデフォルトで有効/無効になっているルールについて調べる機会があったので、ついでにまとめてみました。例については一部しか載せてないので、もっと詳細に知りたい方は各ルールの公式リファレンスを見た方がいいです。
全部で205個ルールあります。
- Default:87
- Opt-in:118
※2021年6月時点の最新版(v0.43.1)を対象としています。
Default
デフォルトで有効になっているルール
Block Based KVO
Swift3.2以降の場合、keypathをもつ新しいブロックベースのKVO APIを使うべき。
(observerValue()をoverrideするのではなく、observe()を呼び出すべき)
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
Delegate protocolはweak
で保持される可能性があるため、class-onlyにするべき。
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.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 Spacing
コロン(:
)は、型を指定するときは識別子の後ろ、Dictonaryではkeyの後ろにあるべき。
https://realm.github.io/SwiftLint/colon.html
// bad
let abc:Void
let abc :Void
let abc : Void
let abc: [Void:Void]
let abc: [Void :Void]
let abc: [Void : Void]
// good
let abc: Void
let abc: [Void: Void]
Comma Spacing
カンマ(,
)の前にスペースがあるべきではない。カンマの後ろにはスペースがあるべき。
https://realm.github.io/SwiftLint/comma.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) { }
Comment Spacing
コメントする場合、スラッシュ(//
)の後ろにスペースを入れるべき。
https://realm.github.io/SwiftLint/comment_spacing.html
// bad
//hogehoge
// good
// hogehoge
Compiler Protocol Init
コンパイラプロトコルで定義されているイニシャライザは直接呼び出すべきではない。
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)
Computed Accessors Order
getterとsetterの順を統一すべき。基本はgetter→setterの順。
https://realm.github.io/SwiftLint/computed_accessors_order.html
// bad
class Foo {
var foo: Int {
set {
print(newValue)
}
get {
return 20
}
}
}
// good
class Foo {
var foo: Int {
get {
return 20
}
set {
print(newValue)
}
}
}
setter→getterにする場合は以下を参照。
Control Statement
if
, for
, guard
, switch
, while
, catch
は条件式や引数を、必要以上に括弧(()
)で囲むべきではない。
https://realm.github.io/SwiftLint/control_statement.html
// bad
if (condition) {
// good
if condition {
Custom Rules
.swiftlint.yml
に記述したcustome_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 { }
}
もう少し詳細に説明すると「関数内の処理は循環的複雑度を10以下にするべき」というルール。
循環的複雑度(英: Cyclomatic complexity)とは、ソフトウェア測定法の一種である。Thomas McCabe が開発したもので、プログラムの複雑度を測るのに使われる。プログラムのソースコードから、線形的に独立した経路の数を直接数える。
wiki
Deployment Target
@available
などを使う場合は、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 14.0, *)
class A {}
if #available(iOS 14.0, *) {}
Discouraged Direct Initialization
有害な可能性のある型を直接初期化すべきではない。
https://realm.github.io/SwiftLint/discouraged_direct_init.html
// bad
UIDevice()
Bundle()
let foo = UIDevice()
let foo = Bundle()
let foo = Bundle.init()
// good
let foo = UIDevice.current
let foo = Bundle.main
let foo = Bundle.init(path: "bar")
Duplicate Enum Cases
enumには同じケース名を含めれない。
https://realm.github.io/SwiftLint/duplicate_enum_cases.html
// bad
enum PictureImport {
case add(image: UIImage)
case addURL(url: URL)
case add(data: Data)
}
// good
enum PictureImport {
case addImage(image: UIImage)
case addData(data: Data)
}
Duplicate Imports
インポートは一意であるべき。同じインポートをするべきではない。
https://realm.github.io/SwiftLint/duplicate_imports.html
// bad
import Foundation
import Dispatch
import Foundation
// good
import Foundation
import Dispatch
Duplicated Key in Dictionary Literal
Dictionaryでは同じKeyを持つべきではない。
https://realm.github.io/SwiftLint/duplicated_key_in_dictionary_literal.html
// bad
[
foo: "1",
bar: "2",
foo: "3",
]
// good
[
foo: "1",
bar: "2"
]
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() {}
}
Empty Enum Arguments
enumの連想値が使われていない場合は、引数を省略すべき。
https://realm.github.io/SwiftLint/empty_enum_arguments.html
// bad
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 Length
ファイルにあまりにも多くの行があってはならない。(ファイル内の処理を別ファイルに分割するなどした方が良い)
https://realm.github.io/SwiftLint/file_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 { return true }
}
// good
for user in users where user.id == 1 { }
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
// bad
func a() throws {}
try! a()
// good
func a() throws {}
do {
try a()
} catch {}
Function Body Length
関数内はあまりにも多くの行にまたがるべきではない。
https://realm.github.io/SwiftLint/function_body_length.html
Function Parameter Count
関数の引数の数は少なくするべき(引数は5つ以下にするべき)
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_Foo>() {}
func foo<TTTTTTTTTTTTTTTTTTTTT>() {}
// good
func foo<T>() {}
Identifier Name
識別子名には、英数字のみを使用し、小文字で始まるか、大文字のみを使用する必要がある。 例外として、変数名が静的で不変であると宣言されている場合、変数名は大文字で始まる場合がある。 変数名は長すぎても短すぎてもいけない。
https://realm.github.io/SwiftLint/identifier_name.html
// bad
let MyLet = 0
let _myLet = 0
let myExtremelyVeryVeryVeryVeryVeryVeryLongLet = 0
// good
let myLet = 0
let URL: NSURL? = nil
Implicit Getter
read-onlyのコンピューテッドプロパティとサブスクリプトでは、get
を使うべきではない。
https://realm.github.io/SwiftLint/implicit_getter.html
// bad
class Foo {
var foo: Int {
get {
return 20
}
}
}
// good
class Foo {
var foo: Int {
get { return 3 }
set { _abc = newValue }
}
}
Inclusive Language
識別子は、人種、性別、または社会経済的地位に基づく人々のグループに対する差別を避ける言葉を使用する必要がある。
https://realm.github.io/SwiftLint/inclusive_language.html
// bad
let slave = "abc"
enum ListType {
case whitelist
case blacklist
}
Inert Defer
defer
が親スコープの最後にある場合、その場で実行される。
https://realm.github.io/SwiftLint/inert_defer.html
// bad
func example0() {
defer { /* deferred code */ }
}
// good
func example3() {
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
// hoge
// good
// hoge
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
hasValue
をoverrideするのではなく、hash(into:)
関数を使うべき。
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行にあまりにも多くの文字を含めるべきではない。(120文字以下にすべき)
https://realm.github.io/SwiftLint/line_length.html
Mark
MARK
コメントは有効な形式にするべき。
https://realm.github.io/SwiftLint/mark.html
// bad
//MARK: bad
// MARK:bad
//MARK:bad
// MARK: bad
// MARK: bad
// MARK: -bad
// MARK:- bad
// MARK:-bad
//MARK: - bad
//MARK:- bad
//MARK: -bad
//MARK:-bad
// MARK bad
//MARK bad
// MARK - bad
//MARK : bad
// MARKL:
// MARKR
// MARKK -
/// MARK:
/// MARK bad
//MARK:- Top-Level bad mark
//MARK:- Another bad mark
struct MarkTest {}
// MARK:- Bad mark
extension MarkTest {}
// good
// MARK: good
// MARK: - good
// MARK: -
// BOOKMARK
// BOOKMARKS
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.map { $0 + 1 }
Nesting
型は最大1レベルの深さにネストするべきであり、関数は最大5レベルの深さにネストするべき。
https://realm.github.io/SwiftLint/nesting.html
// bad
class Example_0 {
class Example_1 {
class Example_2 {}
}
}
// good
class Example_0 {
class Example_1 {}
}
No Fallthrough Only
fallthrough
は、caseに少なくとも1つのステートメントが含まれている場合にのみ使うべき。
https://realm.github.io/SwiftLint/no_fallthrough_only.html
// bad
switch myvar {
case 1:
fallthrough
case 2:
var a = 1
}
// good
switch myvar {
case 1:
var a = 1
fallthrough
case 2:
var a = 2
}
No Space in Method Call
メソッド名と括弧()
の間にスペースを入れてはいけない。
https://realm.github.io/SwiftLint/no_space_in_method_call.html
// bad
foo ()
// good
foo()
Notification Center Detachment
NotificationCenter
に登録した自分自身のobserverはクラスの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)
}
}
class Foo {
func bar() {
NotificationCenter.default.removeObserver(otherObject)
}
}
NSObject Prefer isEqual
NSObject
のサブクラスは、==
の代わりにisEqual
を実装するべき。
https://realm.github.io/SwiftLint/nsobject_prefer_isequal.html
// bad
class AClass: NSObject {
static func ==(lhs: AClass, rhs: AClass) -> Bool {
return false
}
}
// good
class AClass: NSObject {
override func isEqual(_ object: Any?) -> Bool {
return true
}
}
Opening Brace Spacing
{
は宣言と同じ行に置き、スペースを1つ入れるべき。
https://realm.github.io/SwiftLint/opening_brace.html
// bad
func abc(){
}
func abc()
{
}
// good
func abc() {
}
Operator Function Whitespace
演算子を定義する時、1つのスペースで囲むべき。
https://realm.github.io/SwiftLint/operator_whitespace.html
// bad
func <|(lhs: Int, rhs: Int) -> Int {}
// good
func <| (lhs: Int, rhs: Int) -> Int {}
Orphaned Doc Comment
ドキュメントコメントは宣言の上部に書くべき。
https://realm.github.io/SwiftLint/orphaned_doc_comment.html
// bad
/// My great property
// Not a doc string
var myGreatProperty: String!
// good
/// My great property
var myGreatProperty: String!
Private over fileprivate
fileprivate
よりprivate
を使用するべき。
https://realm.github.io/SwiftLint/private_over_fileprivate.html
// 例を見てもよくわからない。とりあえずfileprivateはあまり使わない方がいいということは確か
// bad
fileprivate class MyClass {
fileprivate(set) var myInt = 4
}
fileprivate enum MyEnum {}
// good
class MyClass {
fileprivate(set) var myInt = 4
}
Private Unit Test
private
のUnit Testは暗黙的にスキップされる(privateにすべきではない)
https://realm.github.io/SwiftLint/private_unit_test.html
// bad
private class FooTest: XCTestCase {
func test1() {}
internal func test2() {}
public func test3() {}
}
// good
class FooTest: XCTestCase {
func test1() {}
internal func test2() {}
public func test3() {}
}
Protocol Property Accessors Order
プロトコルでプロパティを宣言する場合、アクセサの順番をget``set
の順にするべき。
https://realm.github.io/SwiftLint/protocol_property_accessors_order.html
// bad
protocol Foo {
var bar: String { set get }
}
// good
protocol Foo {
var bar: String { get set }
}
protocol Foo {
var bar: String { get }
}
protocol Foo {
var bar: String { set }
}
Reduce Boolean
reduce(true)
やreduce(false)
よりも.allSatisfy()
や.contains()
を使うべき。
https://realm.github.io/SwiftLint/reduce_boolean.html
// bad
let allNines = nums.reduce(true) { $0.0 && $0.1 == 9 }
let anyNines = nums.reduce(false) { $0.0 || $0.1 == 9 }
// good
let allNines = nums.allSatisfy { $0 == 9 }
let anyNines = nums.contains { $0 == 9 }
Redundant Discardable Let
関数の戻り値を使わず実行する場合、let _ = foo()
より_ = foo()
を使うべき。
https://realm.github.io/SwiftLint/redundant_discardable_let.html
// bad
let _ = foo()
// 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
Optional型の変数をnil
で初期化するのは冗長。
https://realm.github.io/SwiftLint/redundant_optional_initialization.html
// bad
var myVar: Int? = nil
// good
var myVar: Int?
Redundant Set Access Control Rule
プロパティのセッターのアクセスレベルが、変数のアクセスレベルと同じ場合、明示的に指定すべきではない。
https://realm.github.io/SwiftLint/redundant_set_access_control.html
// bad
private(set) private var foo: Int
// good
private(set) public var foo: Int
Redundant String Enum Value
文字列の列挙値は、caseと同じ場合省略できる。
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
}
Redundant Void Return
関数宣言でVoid
を返すのは冗長である。
https://realm.github.io/SwiftLint/redundant_void_return.html
// bad
func foo() -> Void {}
// good
func foo() {}
Returning Whitespace
戻り値の矢印と型は1つのスペースを開けるか、別の行で区切るべき。
https://realm.github.io/SwiftLint/return_arrow_whitespace.html
// bad
func abc()->Int {}
func abc() ->[Int] {}
func abc()-> (Int, 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 - aVariable
// good
foo -= 1
foo -= variable
Statement Position
else
とcatch
は前の宣言に1つのスペースを入れ、同じ行に配置されるべき。
https://realm.github.io/SwiftLint/statement_position.html
// bad
}else if {
} else {
}
catch {
}
catch {
// good
} else if {
} 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_case_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
シンタックスシュガー(糖衣構文)を使うべき。Array
の代わりに[Int]
を使うなど。
https://realm.github.io/SwiftLint/syntactic_sugar.html
// bad
let x: Array<String>
// good
let x: [Int]
Todo
TODO
とFIXME
は解決すべき。
https://realm.github.io/SwiftLint/todo.html
// bad
// TODO:
// FIXME:
Trailing Comma
配列とDictionaryの末尾のカンマは付けるべきではない。
https://realm.github.io/SwiftLint/trailing_comma.html
// bad
let foo = [1, 2, 3,]
// good
let foo = [1, 2, 3]
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
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 myType {}
// good
class MyType {}
Unneeded Break in Switch
不要なbreak
の使用は避けるべき。
https://realm.github.io/SwiftLint/unneeded_break_in_switch.html
// bad
switch foo {
case .bar:
something()
break
}
// good
switch foo {
case .bar:
break
}
Unused Capture List
キャプチャリスト内の未使用の参照は削除すべき。
https://realm.github.io/SwiftLint/unused_capture_list.html
// bad
[1, 2].map { [weak self] num in
print(num)
}
// good
[1, 2].map { num in
print(num)
}
[1, 2].map { [weak self] num in
self?.handle(num)
}
Unused Closure Parameter
クロージャで使用されてないパラメータは_
に置き換えるべき。
https://realm.github.io/SwiftLint/unused_closure_parameter.html
// bad
[1, 2].map { number in
return 3
}
// good
[1, 2].map { number in
number + 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 }
Unused Enumerated
インデックスかアイテムが使用されてない場合は、.enumerated()
を削除すべき。
https://realm.github.io/SwiftLint/unused_enumerated.html
// bad
for (_, foo) in bar.enumerated() { }
// good
for (index, foo) in bar.enumerated() { }
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
}
}
Valid IBInspectable
@IBInspectable
はサポートされている型の変数のみに適用されるべきであり、その型を明示的にする必要がある。
https://realm.github.io/SwiftLint/valid_ibinspectable.html
// bad
class Foo {
@IBInspectable private let x: Int
}
// good
class Foo {
@IBInspectable private var x: Int
}
Vertical Parameter Alignment
関数の定義時、パラメータが複数行にまたがっている場合は垂直方向に揃えるべき。
https://realm.github.io/SwiftLint/vertical_parameter_alignment.html
// bad
func validateFunction(_ file: SwiftLintFile, kind: SwiftDeclarationKind,
dictionary: SourceKittenDictionary) { }
// good
func validateFunction(_ file: SwiftLintFile, kind: SwiftDeclarationKind,
dictionary: SourceKittenDictionary) { }
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 Delegate
Delegateは循環参照を避けるために弱参照とすべき。
https://realm.github.io/SwiftLint/weak_delegate.html
// bad
var delegate: SomeProtocol?
// good
weak var delegate: SomeProtocol?
XCTFail Message
XCTFail
の呼び出しには、アサーションの説明を含めるべき。
https://realm.github.io/SwiftLint/xctfail_message.html
// bad
func testFoo() {
XCTFail()
}
// good
func testFoo() {
XCTFail("bar")
}
Opt-in
デフォルトで無効になっているルール
AnyObject Protocol
class-onlyなプロトコルにはclass
よりAnyObject
を使うべき。
https://realm.github.io/SwiftLint/anyobject_protocol.html
// bad
protocol SomeClassOnlyProtocol: class {}
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {}
// good
protocol SomeProtocol {}
protocol SomeClassOnlyProtocol: AnyObject {}
Array Init
シーケンスを配列に変換する場合、seq.map { $0 }
よりArray(seq)
を使うべき。
https://realm.github.io/SwiftLint/array_init.html
// bad
foo.map { $0 }
// good
Array(foo)
Attributes
属性は、関数と型では別の行にあるべきだが、変数とimportの場合は同じ行にあるべき。
https://realm.github.io/SwiftLint/attributes.html
// 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
Balanced XCTest life-cycle
テストクラスはsetUp()
とtearDown()
をバランスよく実装すべき。
https://realm.github.io/SwiftLint/balanced_xctest_lifecycle.html
// bad
final class FooTests: XCTestCase {
override func setUp() {}
}
final class FooTests: XCTestCase {
override func setUpWithError() throws {}
}
// good
final class FooTests: XCTestCase {
override func setUp() {}
override func tearDown() {}
}
Capture Variable
作成時にクロージャーが変数をキャプチャーする混乱を避けるために、非定数変数はクロージャーのキャプチャーリストにリストすべきではない。
https://realm.github.io/SwiftLint/capture_variable.html
// bad
var j: Int = 0
let closure: () -> Void = { [j] in
print(j)
}
closure()
j = 1
closure()
// good
var j: Int!
j = 0
let closure: () -> Void = { [j] in
print(j)
}
closure()
j = 1
closure()
Closure Body Length
クロージャ内はあまりにも多くの行にまたがってはいけない。
https://realm.github.io/SwiftLint/closure_body_length.html
// bad
foo.bar { toto in
let a0 = 0
let a0 = 0
let a0 = 0
...
}
// good
foo.bar { toto in
let a0 = 0
}
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)
}
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_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"
]
Conditional Returns on Newline
guard
やif
でreturn
する際は次の行で行うべき。
https://realm.github.io/SwiftLint/conditional_returns_on_newline.html
// bad
guard true else { return }
// good
guard true else {
return
}
Contains Over Filter Count
filter(where:).count
を0と比較するよりcontains
を使うべき。
https://realm.github.io/SwiftLint/contains_over_filter_count.html
// bad
let result = myList.filter(where: { $0 % 2 == 0 }).count > 0
let result = myList.filter(where: { $0 % 2 == 0 }).count == 0
// good
let result = myList.contains { $0 % 2 == 0 }
let result = myList.filter { $0 % 2 == 0 }.count > 1
Contains Over Filter Is Empty
filter(where:).isEmpty
を使うよりcontains
を使うべき。
https://realm.github.io/SwiftLint/contains_over_filter_is_empty.html
// bad
let result = myList.filter(where: { $0 % 2 == 0 }).isEmpty
let result = myList.filter { $0 % 2 == 0 }.isEmpty
// good
let result = myList.contains(where: { $0 % 2 == 0 })
let result = myList.filter(where: { $0 % 2 == 0 }).count > 1
Contains over first not nil
first(where:) != nil
やfirstIndex(where:) != nil
よりもcontains
を使うべき。
https://realm.github.io/SwiftLint/contains_over_first_not_nil.html
// bad
myList.first { $0 % 2 == 0 } != nil
myList.firstIndex { $0 % 2 == 0 } != nil
// good
myList.contains { $0 % 2 == 0 }
myList.contains(where: { $0 % 2 == 0 })
Contains over range(of:) comparison to nil
range(of:) != nil
やrange(of:) == nil
よりもcontains
を使うべき。
https://realm.github.io/SwiftLint/contains_over_range_nil_comparison.html
// bad
myString.range(of: "Test") != nil
myString.range(of: "Test") == nil
// good
myString.contains("Test")
!myString.contains("Test")
Convenience Type
staticメンバーのみをホストするために使われる型は、インスタンス化を避けるために、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
}
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) { }
func foo() -> Any {
return nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })
}
Discouraged Assert
assert(false)
を使うより、assertionFailure()
またはpreconditionFailure()
を使用するべき。
https://realm.github.io/SwiftLint/discouraged_assert.html
// bad
assert(false)
assert(false, "foobar")
// good
preconditionFailure("foobar")
assertionFailure("foobar")
assert(true)
Discouraged None Name
Optional<T>.none
と競合の可能性のあるcase名やstaticメンバー名は推奨しない。
https://realm.github.io/SwiftLint/discouraged_none_name.html
// bad
enum MyEnum {
case none
}
class MyClass {
static let none = MyClass()
}
// good
// 以下はルール的にはセーフだが、noneに似ているので避けた方がいいと思う
enum MyEnum {
case nOne
}
class MyClass {
class var nonenone: MyClass { MyClass() }
}
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?
let foo: Bool? = nil
// good
var foo: Bool
let foo: Bool = true
Discouraged Optional Collection
オプショナルのコレクションを使うより空のコレクションを使うべき。
https://realm.github.io/SwiftLint/discouraged_optional_collection.html
// bad
var foo: [Int]?
let foo: [Int]? = nil
// good
var foo: [Int]
let foo: [Int] = []
Empty Collection Literal
コレクションを空の配列やDictionaryと比較するより、isEmpty
を使うべき。
https://realm.github.io/SwiftLint/empty_collection_literal.html
// bad
myArray == []
myArray != []
myDict == [:]
myDict != [:]
// good
myArray.isEmpty
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() {
}
}
Enum Case Associated Values Count
列挙型のcaseの連想値は少なくするべき(4つ以下にするべき)
https://realm.github.io/SwiftLint/enum_case_associated_values_count.html
// bad
enum Employee {
case fullTime(name: String, retirement: Date, age: Int, designation: String, contactNumber: Int)
case partTime(name: String, contractEndDate: Date, age: Int, designation: String, contactNumber: Int)
}
enum Barcode {
case upc(Int, Int, Int, Int, Int, Int)
}
// good
enum Employee {
case fullTime(name: String, retirement: Date, designation: String, contactNumber: Int)
case partTime(name: String, age: Int, contractEndDate: Date)
}
enum Barcode {
case upc(Int, Int, Int, Int)
}
ExpiringTodo
TODOとFIXMEは有効期限前に解決すべき。
https://realm.github.io/SwiftLint/expiring_todo.html
// bad
// TODO: [1/1/2019]
// FIXME: [1/1/2019]
// good
// TODO: [12/31/9999]
// FIXME: [12/31/9999]
Explicit ACL
全ての宣言で、アクセス制御レベルのキーワードを明示的に指定すべき。
https://realm.github.io/SwiftLint/explicit_acl.html
// bad
enum A {}
final class B {}
internal struct C { let d = 5 }
public struct C { let d = 5 }
func a() {}
// good
internal enum A {}
public final class B {}
private struct C {}
internal enum A {
internal enum B {}
}
internal final class Foo {}
Explicit Enum Raw Value
列挙型のcase
にはローバリューを明示的に割り当てるべき。
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) }
func foo() -> [String] {
return [1].flatMap { String.init($0) }
}
// 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
// bad
struct A {
func f1() {}
func f2() {
f1()
}
}
struct A {
let p1: Int
func f1() {
_ = p1
}
}
// good
struct A {
func f1() {}
func f2() {
self.f1()
}
}
struct A {
let p1: Int
func 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
// bad
class Foo {
var myVar = 0
}
// good
class Foo {
var myVar: Int? = 0
}
Extension Access Modifier
extension
にはアクセス修飾子を使うべき。
https://realm.github.io/SwiftLint/extension_access_modifier.html
// bad
extension Foo {
var bar: Int { return 1 }
var baz: Int { return 1 }
}
// good
public extension Foo {
var bar: Int { return 1 }
var baz: Int { return 1 }
}
extension Foo {
private var bar: Int { return 1 }
public var baz: Int { return 1 }
}
Fallthrough
fallthrough
は使うべきではない。
https://realm.github.io/SwiftLint/fallthrough.html
// bad
switch foo {
case .bar:
fallthrough
case .bar2:
something()
}
// good
switch foo {
case .bar:
hoge()
case .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
各ファイルのヘッダーコメントは、一貫性のあるパターンであるべき。
(ヘッダーコメントの内容は統一すべき的なこと)
https://realm.github.io/SwiftLint/file_header.html
File Name
ファイル名は、ファイル内で宣言されている型やextensionと一致すべき。
https://realm.github.io/SwiftLint/file_name.html
File Name No Space
ファイル名にはスペースが入ってはいけない。
https://realm.github.io/SwiftLint/file_name_no_space.html
File Types Order
ファイル内の型の表示順を指定すべき。
https://realm.github.io/SwiftLint/file_types_order.html
// bad
// `protocol` (サポートする型)は `class` (主となる型)の前に書くべき
class TestViewController: UIViewController {}
protocol TestViewControllerDelegate {
func didPressTrackedButton()
}
// `extension` は `class` の後に書くべき
extension TestViewController: UITableViewDataSource { // (省略) }
class TestViewController: UIViewController {}
// good
// Supporting Types
protocol TestViewControllerDelegate: AnyObject {
func didPressTrackedButton()
}
// Main Type
class TestViewController: UIViewController {
// Type Aliases
typealias CompletionHandler = ((TestEnum) -> Void)
// Subtypes
class TestClass {
// 10 lines
}
struct TestStruct {
// 3 lines
}
enum TestEnum {
// 5 lines
}
// Stored Type Properties
static let cellIdentifier: String = "AmazingCell"
// Stored Instance Properties
var shouldLayoutView1: Bool!
weak var delegate: TestViewControllerDelegate?
private var hasLayoutedView1: Bool = false
private var hasLayoutedView2: Bool = false
// Computed Instance Properties
private var hasAnyLayoutedView: Bool {
return hasLayoutedView1 || hasLayoutedView2
}
// IBOutlets
@IBOutlet private var view1: UIView!
@IBOutlet private var view2: UIView!
// Initializers
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Type Methods
static func makeViewController() -> TestViewController {
return TestViewController()
}
// Life-Cycle Methods
override func viewDidLoad() {
super.viewDidLoad()
view1.setNeedsLayout()
view1.layoutIfNeeded()
hasLayoutedView1 = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view2.setNeedsLayout()
view2.layoutIfNeeded()
hasLayoutedView2 = true
}
// IBActions
@IBAction func goNextButtonPressed() {
goToNextVc()
delegate?.didPressTrackedButton()
}
@objc
func goToRandomVcButtonPressed() {
goToRandomVc()
}
// MARK: Other Methods
func goToNextVc() { /* TODO */ }
func goToInfoVc() { /* TODO */ }
func goToRandomVc() {
let viewCtrl = getRandomVc()
present(viewCtrl, animated: true)
}
private func getRandomVc() -> UIViewController { return UIViewController() }
// Subscripts
subscript(_ someIndexThatIsNotEvenUsed: Int) -> String {
get {
return "This is just a test"
}
set {
print("Just a test \(newValue)")
}
}
}
// Extensions
extension TestViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
}
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 }
FlatMap over map and reduce
reduce([], +)
が後に続くmap
よりもflatMap
を使うべき。
https://realm.github.io/SwiftLint/flatmap_over_map_reduce.html
// bad
let foo = bar.map { $0.array }.reduce([], +)
// good
let foo = bar.flatMap { $0.array }
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) { }
IBInspectable in Extension
extensionには@IBInspectable
プロパティを追加すべきではない。
https://realm.github.io/SwiftLint/ibinspectable_in_extension.html
// bad
extension Foo {
@IBInspectable private var x: Int
}
// good
class Foo {
@IBInspectable private var x: Int
}
Identical Operands
同一のオペランドを比較するのは間違っている可能性がある。
https://realm.github.io/SwiftLint/identical_operands.html
// bad
1 == 1
foo == foo
// good
1 == 2
foo == bar
Implicit Return
クロージャ、関数、ゲッターでは暗黙的なリターンを使うべき。
https://realm.github.io/SwiftLint/implicit_return.html
// bad
foo.map {
return $0 + 1
}
func foo() -> Int {
return 0
}
class Foo {
var bar: Int {
get {
return 0
}
}
}
// good
foo.map { $0 + 1 }
func foo() -> Int {
0
}
class Foo {
var bar: Int {
get {
0
}
}
}
Implicitly Unwrapped Optional
暗黙的にアンラップされているオプショナル型は可能な限り使うべきではない。
https://realm.github.io/SwiftLint/implicitly_unwrapped_optional.html
// bad
var int: Int! = 42
let label: UILabel!
// good
let int: Int? = 42
@IBOutlet var label: UILabel!
Indentation Width
1つのタブまたは設定したスペースの量でコードをインデントすべき。
https://realm.github.io/SwiftLint/indentation_width.html
// bad
firstLine
secondLine
// good
firstLine
secondLine
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 Multiple
剰余演算子%
を使うよりisMultiple(of:)
を使うべき。
https://realm.github.io/SwiftLint/legacy_multiple.html
// bad
let constant = 56
let isMultiple = value % constant == 0
// good
let constant = 56
let isMultiple = value.isMultiple(of: constant)
Legacy Objective-C Reference Type
bridgeされたObjective-Cの参照型よりSwiftの値型を使うべき。
https://realm.github.io/SwiftLint/legacy_objc_type.html
// bad
var array = NSArray()
var calendar: NSCalendar? = nil
// good
var array = Array<Int>()
var calendar: Calendar? = nil
Legacy Random
従来の関数よりtype.random(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/let_var_whitespace.html
// bad
let a = 0
var x = 1
x = 2
// good
let a = 0
var x = 1
x = 2
Literal Expression End Indentation
配列とdictionaryのリテラルの末尾は、開始した行と同じインデントにするべき。
https://realm.github.io/SwiftLint/literal_expression_end_indentation.html
// bad
let x = [
1,
2
]
let x = [
1,
2
]
let x = [
key: value
]
// good
[1, 2, 3]
[1,
2
]
[
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 { override public func b() {} }
/// docs
public class B: NSObject {
// オーバーライドメソッドはOK
override public var description: String { fatalError() } }
/// docs
public class A {
deinit {}
}
}
Modifier Order
修飾子の順序は一貫しているべき。
https://realm.github.io/SwiftLint/modifier_order.html
// bad
public class Foo {
static public let bar = 42
}
// good
public class Foo {
public static let bar = 42
}
Multiline Arguments
引数は同じ行に置くか、1行に1つずつ指定すべき。
https://realm.github.io/SwiftLint/multiline_arguments.html
// bad
foo(0,
param1: 1, param2: true, param3: [3])
foo(0, param1: 1,
param2: true, param3: [3])
// good
foo(0)
foo(param1: 1, param2: true) { }
foo(param1: 1,
param2: true,
param3: [3])
Multiline Arguments Brackets
複数行の引数には、新しい行に括弧をつけるべき。
https://realm.github.io/SwiftLint/multiline_arguments_brackets.html
// bad
foo(param1: "Param1", param2: "Param2",
param3: "Param3"
)
foo(
param1: "Param1",
param2: "Param2",
param3: "Param3")
foo(bar(
x: 5,
y: 7
)
)
// good
foo(param1: "Param1", param2: "Param2", param3: "Param3")
foo(
param1: "Param1", param2: "Param2", param3: "Param3"
)
func foo(
param1: "Param1",
param2: "Param2",
param3: "Param3"
)
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, +)
let evenSquaresSum = a.b(1, 2, 3)
.c { blah in
print(blah)
}.d()
// 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, +)",
let chain = a
.b(1, 2, 3)
.c { blah in
print(blah)
}
.d()
Multiline Literal Brackets
複数行のリテラルの場合、新しい行に括弧をつけるべき。
https://realm.github.io/SwiftLint/multiline_literal_brackets.html
// bad
let trio = ["harry",
"ronald",
"hermione"
]
let houseCup = ["gryffinder": 460, "hufflepuff": 370,
"ravenclaw": 410, "slytherin": 450
]
// 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) { }
func foo(param1: Int,
param2: Bool,
param3: [String]) { }
Multiline Parameters Brackets
複数行の引数は、新しい行に括弧をつけるべき。
https://realm.github.io/SwiftLint/multiline_parameters_brackets.html
// bad
func foo(param1: String, param2: String,
param3: String
)
func foo(
param1: String,
param2: String,
param3: String)
// good
func foo(param1: String, param2: String, param3: String)
func foo(
param1: String, param2: String, param3: String
)
func foo(
param1: String,
param2: String,
param3: String
)
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
extensionにアクセス修飾子をつけるべきではない。
https://realm.github.io/SwiftLint/no_extension_access_modifier.html
// bad
private extension String {}
// good
extension String {}
No Grouping Extension
同じソースファイル内のコードをグループ化するためにextensionを使用すべきではない。
https://realm.github.io/SwiftLint/no_grouping_extension.html
// bad
enum Fruit {}
extension Fruit {}
struct Tea {}
extension Tea: Error {}
// good
// プロトコルのデフォルト実装はOK
protocol Food {}
extension Food {}
NSLocalizedString Key
genstringsが機能するためには、NSLocalizedString
のkeyとして静的文字列を使うべき。
https://realm.github.io/SwiftLint/nslocalizedstring_key.html
// bad
NSLocalizedString(method(), comment: "")
NSLocalizedString("key_\(param)", comment: "")
// good
NSLocalizedString("key", comment: "")
NSLocalizedString("key" + "2", comment: "")
NSLocalizedString Require Bundle
NSLocalizedString
の呼び出しは、文字列ファイルを含むバンドルを指定する必要がある。
https://realm.github.io/SwiftLint/nslocalizedstring_require_bundle.html
// bad
NSLocalizedString("someKey", comment: "test")
NSLocalizedString("someKey", tableName: "a", comment: "test")
NSLocalizedString("someKey", tableName: "xyz",
value: "test", comment: "test")
// good
NSLocalizedString("someKey", bundle: .main, comment: "test")
NSLocalizedString("someKey", tableName: "a",
bundle: Bundle(for: A.self),
comment: "test")
NSLocalizedString("someKey", tableName: "xyz",
bundle: someBundle, value: "test"
comment: "test")
Number Separator
_
は十進数で千の区切り文字として使うべき。
https://realm.github.io/SwiftLint/number_separator.html
// bad
let foo = -10_0
let foo = -1000
// good
let foo = -1_000
let foo = -1_000_000
let foo = -1.000_1
Object Literal
画像や色はイニシャライザよりもオブジェクトリテラルを使うべき。
https://realm.github.io/SwiftLint/object_literal.html
// bad
let image = UIImage(named: "foo")
let color = UIColor(red: 0.3, green: 0.3, blue: 0.3, alpha: 1)
// good
let image = #imageLiteral(resourceName: "image.jpg")
let color = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)
Operator Usage Whitespace
演算子を使用するときは、演算子をスペースで囲むべき。
https://realm.github.io/SwiftLint/operator_usage_whitespace.html
// bad
let foo =1+2
let foo = 1 > 2
// good
let foo = 1 + 2
let foo = 1 > 2
Optional Enum Case Match
?
のないオプショナルの列挙型に対する、列挙型のケースの一致は、Swift5.1以降でサポートされる。
(Swift5.1以降を使用してない場合はこの方法は使用できない。)
https://realm.github.io/SwiftLint/optional_enum_case_matching.html
// bad
switch foo {
case .bar?: break
case .baz: break
default: break
}
// good
switch foo {
case .bar: break
case .baz: break
default: break
}
Overridden methods call super
一部のオーバーライドメソッドは、常にsuper
を呼び出す必要がある。
https://realm.github.io/SwiftLint/overridden_super_call.html
// bad
class VC: UIViewController {
override func viewWillAppear(_ animated: Bool) {
//Not calling to super
self.method()
}
}
class VC: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Other code
super.viewWillAppear(animated)
}
}
class VC: UIViewController {
override func didReceiveMemoryWarning() {
}
}
// good
class VC: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
}
class VC: UIViewController {
override func viewWillAppear(_ animated: Bool) {
self.method1()
super.viewWillAppear(animated)
self.method2()
}
}
class VC: UIViewController {
override func loadView() {
}
}
class Some {
func viewWillAppear(_ animated: Bool) {
}
}
class VC: UIViewController {
override func viewDidLoad() {
defer {
super.viewDidLoad()
}
}
}
Override in Extension
extensionでは定義をoverrideすべきではない。
https://realm.github.io/SwiftLint/override_in_extension.html
// bad
extension Person {
override var age: Int { return 42 }
}
extension Person {
override func celebrateBirthday() {}
}
// good
extension Person {
var age: Int { return 42 }
}
extension Person {
func celebrateBirthday() {}
}
Pattern Matching Keywords
キーワードをタプルの外に出し、複数のパターンマッチングバインディングを組み合わせるべき。
https://realm.github.io/SwiftLint/pattern_matching_keywords.html
// bad
switch foo {
case (let x, let y): break
}
// good
switch foo {
case let (x, y): break
}
Prefer Nimble
XCTAssert
関数よりNimbleマッチャーを使うべき。
https://realm.github.io/SwiftLint/prefer_nimble.html
// bad
XCTAssertTrue(foo)
XCTAssertEqual(foo, 2)
// good
expect(foo) == 1
expect(foo).to(equal(1))
Prefer Self Type Over Type of Self
プロパティにアクセスするときや、メソッドを呼び出すときは、type(of: self)
よりSelfを使うべき。
https://realm.github.io/SwiftLint/prefer_self_type_over_type_of_self.html
// bad
class Foo {
func bar() {
type(of: self).baz()
}
}
// good
class Foo {
func bar() {
Self.baz()
}
}
Prefer Zero Over Explicit Init
パラメータが0の明示的な初期化(例:CGPoint(x: 0, y: 0)
)より.zero
を使うべき。
https://realm.github.io/SwiftLint/prefer_zero_over_explicit_init.html
// bad
CGPoint(x: 0, y: 0)
// good
CGPoint.zero
Prefixed Top-Level Constant
最上位の定数には、定数名の先頭にk
をつけるべき。
https://realm.github.io/SwiftLint/prefixed_toplevel_constant.html
// bad
private let foo = 20.0
// good
private let kFoo = 20.0
Private Actions
@IBAction
はprivate
にすべき。
https://realm.github.io/SwiftLint/private_action.html
// bad
@IBAction func barButtonTapped(_ sender: UIButton) {}
// good
@IBAction private func barButtonTapped(_ sender: UIButton) {}
Private Outlets
@IBOutlet
はprivate
にすべき。(上位レイヤーにUIKit
が漏洩するのを防ぐため)
https://realm.github.io/SwiftLint/private_outlet.html
// bad
@IBOutlet var label: UILabel?
// good
@IBOutlet private var label: UILabel?
Private Combine Subject
Combine Subjectはprivate
にするべき。
https://realm.github.io/SwiftLint/private_subject.html
// bad
final class Foobar {
let goodSubject = PassthroughSubject<Bool, Never>()
}
// good
final class Foobar {
private let goodSubject = PassthroughSubject<Bool, Never>()
}
Prohibited Interface Builder
IB(InterfaceBuilder)を使ってViewを生成するのは避けるべき。
https://realm.github.io/SwiftLint/prohibited_interface_builder.html
// bad
class ViewController: UIViewController {
@IBOutlet var label: UILabel!
@IBAction func buttonTapped(_ sender: UIButton) {}
}
// good
class ViewController: UIViewController {
var label: UILabel!
@objc func buttonTapped(_ sender: UIButton) {}
}
Prohibited calls to super
一部のメソッドはsuper
(親クラスのメソッド)を呼び出すべきではない。
https://realm.github.io/SwiftLint/prohibited_super_call.html
// bad
class VC: UIViewController {
override func loadView() {
super.loadView()
}
}
Quick Discouraged Call
describe
やcontext
内で推奨されない呼び出し。
https://realm.github.io/SwiftLint/quick_discouraged_call.html
// bad
class TotoTests: QuickSpec {
override func spec() {
describe("foo") {
let foo = Foo()
}
}
}
// good
class TotoTests: QuickSpec {
override func spec() {
describe("foo") {
beforeEach {
let foo = Foo()
foo.toto()
}
}
}
}
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")
}
}
Raw Value For Camel Cased Codable Enum
Codable
とString
を継承した列挙型のCamelケースの場合は値を持つべき。
https://realm.github.io/SwiftLint/raw_value_for_camel_cased_codable_enum.html
// bad
enum Status: String, Codable {
case ok
case notAcceptable
case maybeAcceptable = "maybe_acceptable"
}
// good
enum Status: String, Codable {
case ok
case notAcceptable = "not_acceptable"
case maybeAcceptable = "maybe_acceptable"
}
Reduce Into
copy-on-writeの場合、reduce(_:_:)
よりreduce(into:_:)
を使うべき。
https://realm.github.io/SwiftLint/reduce_into.html
// bad
let bar = values.reduce("abc") { $0 + "\($1)" }
// good
let foo = values.reduce(into: "abc") { $0 += "\($1)" }
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()
var isEnabled: Bool = true
// 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, error
}
// good
enum MyNetworkResponse: String, NetworkResponsable {
case success, error, notConnected
}
enum MyNetworkResponse: String, NetworkResponsable {
case success, error, 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: QuickSpec { }
class BarTests: XCTestCase { }
// good
class FooTests: QuickSpec { }
class FooTests: XCTestCase { }
Min or Max over Sorted First or Last
sorted().first
やsorted().last
よりmin()
やmax()
を使うべき。
https://realm.github.io/SwiftLint/sorted_first_last.html
// bad
myList.sorted().first
myList.sorted().last
// good
let min = myList.min()
let max = myList.max()
Sorted Imports
import文はソートされるべき。
https://realm.github.io/SwiftLint/sorted_imports.html
// bad
import AAA
import ZZZ
import BBB
import CCC
// 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
class MyClass {
fileprivate let myInt = 4
}
// good
class MyClass {
private let myInt = 4
}
Strong IBOutlet
@IBOutlet
はweak
で定義すべきではない。
https://realm.github.io/SwiftLint/strong_iboutlet.html
// bad
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel?
}
// good
class ViewController: UIViewController {
@IBOutlet 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
}
Test case accessibility
テストケースには、private
の非テストメンバーのみ含めるべき。
https://realm.github.io/SwiftLint/test_case_accessibility.html
// bad
class FooTests: XCTestCase {
var foo: String?
let bar: String?
static func foo() {}
func setUp(withParam: String) {}
func foobar() {}
func not_testBar() {}
enum Nested {}
static func testFoo() {}
static func allTests() {}
func testFoo(hasParam: Bool) {}
}
// good
let foo: String?
class FooTests: XCTestCase {
static let allTests: [String] = []
private let foo: String {
let nestedMember = "hi"
return nestedMember
}
override static func setUp() {
super.setUp()
}
override func setUp() {
super.setUp()
}
override func setUpWithError() throws {
try super.setUpWithError()
}
override static func tearDown() {
super.tearDown()
}
override func tearDown() {
super.tearDown()
}
override func tearDownWithError() {
try super.tearDownWithError()
}
override func someFutureXCTestFunction() {
super.someFutureXCTestFunction()
}
func testFoo() {
XCTAssertTrue(true)
}
func testBar() {
func nestedFunc() {}
}
private someFunc(hasParam: Bool) {}
}
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 })
// good
foo.map { $0 + 1 }
Type Contents Order
型内のサブクラス、プロパティ、メソッドの定義順は従うべき。
https://realm.github.io/SwiftLint/type_contents_order.html
// bad
class TestViewController: UIViewController {
// Subtypes
class TestClass {
// 10 lines
}
// Type Aliases
typealias CompletionHandler = ((TestEnum) -> Void)
}
class TestViewController: UIViewController {
// Stored Type Properties
static let cellIdentifier: String = "AmazingCell"
// Subtypes
class TestClass {
// 10 lines
}
}
class TestViewController: UIViewController {
// Stored Instance Properties
var shouldLayoutView1: Bool!
// Stored Type Properties
static let cellIdentifier: String = "AmazingCell"
}
// good
class TestViewController: UIViewController {
// Type Aliases
typealias CompletionHandler = ((TestEnum) -> Void)
// Subtypes
class TestClass {
// 10 lines
}
struct TestStruct {
// 3 lines
}
enum TestEnum {
// 5 lines
}
// Type Properties
static let cellIdentifier: String = "AmazingCell"
// Instance Properties
var shouldLayoutView1: Bool!
weak var delegate: TestViewControllerDelegate?
private var hasLayoutedView1: Bool = false
private var hasLayoutedView2: Bool = false
private var hasAnyLayoutedView: Bool {
return hasLayoutedView1 || hasLayoutedView2
}
// IBOutlets
@IBOutlet private var view1: UIView!
@IBOutlet private var view2: UIView!
// Initializers
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Type Methods
static func makeViewController() -> TestViewController {
// some code
}
// View Life-Cycle Methods
override func viewDidLoad() {
super.viewDidLoad()
view1.setNeedsLayout()
view1.layoutIfNeeded()
hasLayoutedView1 = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view2.setNeedsLayout()
view2.layoutIfNeeded()
hasLayoutedView2 = true
}
// IBActions
@IBAction func goNextButtonPressed() {
goToNextVc()
delegate?.didPressTrackedButton()
}
// Other Methods
func goToNextVc() { /* TODO */ }
func goToInfoVc() { /* TODO */ }
func goToRandomVc() {
let viewCtrl = getRandomVc()
present(viewCtrl, animated: true)
}
private func getRandomVc() -> UIViewController { return UIViewController() }
// Subscripts
subscript(_ someIndexThatIsNotEvenUsed: Int) -> String {
get {
return "This is just a test"
}
set {
log.warning("Just a test", newValue)
}
}
deinit {
log.debug("deinit")
},
}
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) -> Bool in
return true
}
// good
let foo = { bar -> Bool in
return true
}
Unowned Variable Capture
クラッシュの可能性を回避するため、弱参照にしてキャプチャするべき。
https://realm.github.io/SwiftLint/unowned_variable_capture.html
// bad
foo { [unowned self] in _ }
foo { [unowned bar] in _ }
foo { [bar, unowned self] in _ }
// good
foo { [weak self] in _ }
foo { [weak self] param in _ }
foo { [weak bar] in _ }
foo { [weak bar] param in _ }
Untyped Error in Catch
catch
で、型キャストなしのエラー変数を定義すべきではない。
https://realm.github.io/SwiftLint/untyped_error_in_catch.html
// bad
do {
try foo()
} catch var error {}
// good
do {
try foo()
} catch let error as MyError {
} catch {}
Unused Declaration
定義は少なくとも1回は全てのファイル内のどこかで参照されるべき。
https://realm.github.io/SwiftLint/unused_declaration.html
// bad
let foo = 0
// good
let foo = 0
_ = foo
Unused Import
importされた全てのモジュールが、ファイルをコンパイルするために必要とされるべき。
https://realm.github.io/SwiftLint/unused_import.html
// bad
import Foundation
class A { }
// good
import Foundation
@objc
class A { }
Vertical Parameter Alignment On Call
関数を呼び出す時に、パラメータが複数行にまたがる場合は垂直に揃えるべき。
https://realm.github.io/SwiftLint/vertical_parameter_alignment_on_call.html
// bad
foo(param1: 1, param2: bar
param3: false, param4: true)
foo(param1: 1, param2: bar
param3: false, param4: true)
foo(param1: 1, param2: bar
param3: false,
param4: true)
// good
foo(param1: 1, param2: bar
param3: false, param4: true)
foo(param1: 1, param2: bar)
foo(param1: 1, param2: bar
param3: false,
param4: true)
Vertical Whitespace Between Cases
switch
文内のcase
と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_closing_braces.html
// bad
[
1,
2,
3
]
do {
print("x is 5")
}
// good
[
1,
2,
3
]
do {
print("x is 5")
}
Vertical Whitespace after Opening Braces
中括弧を開いた後に空白行を入れるべきではない。
https://realm.github.io/SwiftLint/vertical_whitespace_opening_braces.html
// bad
[
1,
2,
3
]
do {
print("x is 5")
}
// good
[
1,
2,
3
]
do {
print("x is 5")
}
XCTest Specific Matcher
XCTAssertEqual
やXCTAssertNotEqual
より、特定のXCTestマッチャーを使うべき。
https://realm.github.io/SwiftLint/xct_specific_matcher.html
// bad
XCTAssertEqual(foo, true)
XCTAssertEqual(foo, false)
XCTAssertEqual(foo, nil)
XCTAssertNotEqual(foo, true)
XCTAssertNotEqual(foo, false)
// good
XCTAssertFalse(foo)
XCTAssertTrue(foo)
XCTAssertNil(foo)
XCTAssertNotNil(foo)
XCTAssertEqual(foo, 2)
XCTAssertNotEqual(foo, "false")
Yoda condition rule
変数は比較演算子の左側に配置し、定数は右側に配置すべき。
https://realm.github.io/SwiftLint/yoda_condition.html
// bad
if 42 == foo {}
// good
if foo == 42 {}
おわりに
こうして全体的にルールを見てみると、Opt-inのルールにも意外と使えそうというかDefault(有効)になってていいと思うルールも結構ありました。Conditional Returns on Newline(guardのreturnは改行すべきというルール)などについてはよく論争が起きている気がするので、チーム全体で吟味して有効/無効にしても良さそうだなと特に思います。
全ルールをまとめてみると「こういう書き方もあるんだな」って気づきがあるのでおすすめです。(因みにまとめるのに数日かかりました。)
参考
こちら参考にさせていただきました🙇♂️