iOS/Project Related

coding convention - swiftLint -2

@서비 2022. 8. 30. 01:09

 

우선은 기본적으로 적용되는 1) 룰을 둘러보고, 2) 추가 하거나 제외 할 룰을 생각해보고, 3) 제외할 파일을 생각해본다.

 

 

Default Rules

addObserver 형태가 아닌 블럭 형태의 새로운 API로 사용

// 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)
}

 

델리게이트 프로토콜은 클래스만 사용해야 한다는 의미 (weak 형태의 참조가 필요함) 

// bad
protocol FooDelegate { }

// good
protocol FooDelegate: class { }

 

닫는 괄호에 스페이스를 두지 말라는 의미

// bad
[].map({ } )

// good
[].map({ })

 

클로저의 파라매터를 괄호 좌측에 두라는 의미

// bad
[1, 2].map {
    number in
    number + 1
}

// good
[1, 2].map { number in
    number + 1
}

:을 사용할 때 식별자 뒤에, Dictionary에서는 키 뒤에 위치 

// 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]

쉼표 앞에는 공백이 없어야 하고, 뒤에는 공백이 1개 만큼 있어야 함

// 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) { }

슬러쉬 다음에 1칸의 스페이스 공간을 두라는 의미

// bad
//MARK

// good
// MARK

컴파일 프로토콜에 정의된 이니셜라이저는 직접 호출해서는 안됩니다.

(잘 이해는 안되는데, 용도가 아니라서 쓰지 말라는 의미로 이해함.)

// 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)

get 을 set 보다 먼저 작성

// bad
class Foo {
    var foo: Int {
        ↓set {
            print(newValue)
        }
        get {
            return 20
        }
    }
}

//good
extension Foo {
    var bar: Bool {
        get { _bar }
        set { self._bar = newValue }
    }
}

if, for, guard, switch, while, catch문은 조건이나 인수를 불필요하게 괄호로 묶지 않는다.

// 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 {
}

별도로 정의한 규칙이 있을 경우

함수 내부를 복잡하게 구성하면 안됩니다.

// 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 { }
}

타겟이 12버전인데 6 버전에서의 코드가 있으면 안됩니다.

// bad
@available(iOS 6.0, *)
class A { }

if #available(iOS 6.0, *) { }

// good
@available(iOS 12.0, *)
class A { }

if #available(iOS 12.0, *) { }

직접초기화는 해로울 수 있습니다.

// 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")

같은 이름으로 이넘 케이스를 정의 하지 않도록 합니다.

// 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)
}
// bad
↓import Foundation.NSString
import Foundation

//good
import A // module
import B // module

 

 

 

참조:

https://realm.github.io/SwiftLint/rule-directory.html

https://qiita.com/uhooi/items/7f5d6cf2b240f60ba1ed