-
Notifications
You must be signed in to change notification settings - Fork 8
Code Convention
-
들여쓰기에는 탭(tab)을 사용합니다.
-
콜론(
:
)을 쓸 때에는 콜론의 오른쪽에만 공백을 둡니다.let names: [String: String]?
-
함수 정의가 최대 길이를 초과하는 경우에는 아래와 같이 줄바꿈합니다.
func collectionView( _ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath ) -> UICollectionViewCell { // doSomething() } func animationController( forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController ) -> UIViewControllerAnimatedTransitioning? { // doSomething() }
-
함수 호출 코드가 최대 길이를 초과하는 경우에는 파라미터 이름을 기준으로 줄바꿈합니다.
let actionSheet = UIActionSheet( title: "정말 계정을 삭제하실 건가요?", delegate: self, cancelButtonTitle: "취소", destructiveButtonTitle: "삭제해주세요" )
-
if let
구문이 길 경우에는 줄바꿈하고 한 칸 들여씁니다.if let user = self.veryLongFunctionNameWhichReturnsOptionalUser(), let name = user.veryLongFunctionNameWhichReturnsOptionalName(), user.gender == .female { // ... }
-
guard let
구문이 길 경우에는 줄바꿈하고 한 칸 들여씁니다.else
는guard
와 같은 들여쓰기를 적용합니다.guard let user = self.veryLongFunctionNameWhichReturnsOptionalUser(), let name = user.veryLongFunctionNameWhichReturnsOptionalName(), user.gender == .female else { return }
-
인자가 없는 함수의 연속적 호출은 개행을 하지 않는다.
someThing.firstFunc().secondFunc().End()
단, SwiftUI View의 Modifier는 예외를 둔다.
``` swift Text("This is Text") .bold() .padding() ```
-
인자가 있는 함수의 호출과 후행 클로저가 있는 경우엔 개행을 한다. 단, 첫번째 호출되는 코드에 대해서는 예외를 둔다.
// ex. 1 someThing.singleFunc(with: parameter) .secondFunc(with: someValue) .End(to: endValue) // ex. 2 someThing.map { $0 * 2 } .reduce(0) { result, intValue in result + intValue }
-
self
,Self
키워드에는 개행을 하지 않고, 작성합니다.self.myProperty.setting() Self.self
-
한 줄은 최대 120자를 넘지 않아야 합니다.
- 단,
if let
,guard let
구문은 최대 70자로 제한
Xcode의 Preferences → Text Editing → Display의 'Page guide at column' 옵션을 활성화하고 120자로 설정하면 편리합니다.
- 단,
모듈 임포트는 알파벳 순으로 정렬합니다.
내장 프레임워크를 먼저 임포트하고, 빈 줄로 구분하여 서드파티 프레임워크를 임포트합니다.
- 클래스 이름에는 UpperCamelCase를 사용합니다.
- 클래스 이름에는 접두사를 붙이지 않습니다.
-
함수 이름에는 lowerCamelCase를 사용합니다.
-
함수 이름 앞에는 되도록이면
get
을 붙이지 않습니다.-
좋은 예:
func name(for user: User) -> String?
-
나쁜 예:
func getName(for user: User) -> String?
-
-
Action 함수의 네이밍은 '주어 + 동사 + 목적어' 형태를 사용합니다.
- Tap(눌렀다 뗌)*은
UIControlEvents
의.touchUpInside
에 대응하고, *Press(누름)*는.touchDown
에 대응합니다. - will~은 특정 행위가 일어나기 직전이고, did~는 특정 행위가 일어난 직후입니다.
-
should~는 일반적으로
Bool
을 반환하는 함수에 사용됩니다.
좋은 예:
func backButtonDidTap() { // ... }
나쁜 예:
func back() { // ... } func pressBack() { // ... }
- Tap(눌렀다 뗌)*은
- 변수 이름에는 lowerCamelCase를 사용합니다.
-
상수 이름에는 lowerCamelCase를 사용합니다.
좋은 예:
let maximumNumberOfLines = 3
나쁜 예:
let MaximumNumberOfLines = 3 let MAX_LINES = 3
-
enum의 각 case에는 lowerCamelCase를 사용합니다.
좋은 예:
enum Result { case .success case .failure }
나쁜 예:
enum Result { case .Success case .Failure }
-
약어로 시작하는 경우 소문자로 표기하고, 그 외의 경우에는 항상 대문자로 표기합니다.
좋은 예:
let userID: Int? let html: String? let websiteURL: URL? let urlString: String?
나쁜 예:
let userId: Int? let HTML: String? let websiteUrl: NSURL? let URLString: String?
-
View, ViewModel에 해당하는 개념은 끝에 View, ViewModel을 붙인다.
ex) class SoundViewModel class SettingView
-
Model에 해당하는 개념은 Model을 붙이지 않고, 개념 그대로를 이름으로 사용한다.
ex) struct Sound struct PlayList
-
Singleton 객체는 Manager, Controller, Service 중 하나를 붙인다.
ex) enum NetworkManager struct AppController struct BackgroundSoundController class NotificationService
- 클래스와 구조체 내부에서는
self
를 명시적으로 사용합니다. - 내장 라이브러리가 존재한다면, 불필요한 초기화 함수를 재구성 하지 않습니다.
let frame = CGRect(x: 0, y: 0, width: 100, height: 100)
-
Array<T>
와Dictionary<T: U>
보다는[T]
,[T: U]
를 사용합니다.// 좋은 예: var messages: [String]? var names: [Int: String]? // 나쁜 예: var messages: Array<String>? var names: Dictionary<Int, String>?
-
Int
,Float
,String
,Bool
타입은 변수/상수 선언 시, 명시하지 않습니다.var isShowAnyView = false var referenceCount = 0
-
ViewBuilder의 이름은 대문자로 시작합니다.
-
하나의 View안에서 사용되는 ViewBuilder라면 같은 파일 안에서 extension을 사용하고, MARK를 남깁니다.
struct SomeView: View { // Code } // MARK: - ViewBuilder extension SomeView { @ViewBuilder func BuildView() -> some View { // 대문자로 시작 // Code } }
-
여러 View에서 사용되는 ViewBuilder라면 ViewBuilder가 아닌 View로 정의하여 파일을 분리합니다.
-
파라미터와 리턴 타입이 없는 Closure 정의시에는
() -> Void
를 사용합니다.let completionBlock: (() -> Void)?
-
Closure 작성 시 줄 수에 따라 개행하여 코드 블럭을 작성합니다.
-
1줄 표현식의 경우, 선택적으로 개행하여 작성합니다.
단, 클로져 인자 라벨은 줄 수에 포함하지 않습니다.
oneLineIntArray.map { $0 * 2 } oneLineIntArray.map { $0 * 2 } oneLineIntArray.map { age in age * 2 }
- 2줄 이상의 표현식의 경우, 반드시 개행하여 작성합니다.
intArray.map { let age = $0 * 2 return Person(age: age) }
-
-
Closure 인자 작성 시, 가능한 경우 타입 정의를 생략합니다.
intArray.map { $0 * 2 }
-
인자 라벨의 정의는 필수가 아닌 권장사항이지만, Closure 내의 코드블럭이 2줄 이상인 경우 반드시 라벨을 사용합니다.
intArray.map { intValue in let isOdd = (intValue % 2 == 1) return isOdd }
-
-
Closure 정의시 파라미터에는 괄호를 사용하지 않습니다.
{ operation, responseObject in // doSomething() }
-
Closure 호출시 또 다른 유일한 Closure를 마지막 파라미터로 받는 경우(후행 클로저), 파라미터 이름을 생략합니다.
좋은 예:
UIView.animate(withDuration: 0.5) { // doSomething() }
단, 파라미터에 후행 클로저가 2개 이상 존재하는 경우에는 아래 두 가지 조건을 준수합니다.
- 모든 클로저는 축약 표현을 사용합니다.
- 두번째 클로저부터는 앞에 있는 클로저의 끝
}
에서 줄바꿈을 하지 않고 라벨을 표시합니다.
// UIView.animate(withDuration: TimeInterval, animations: () -> Void, completion: ((Bool) -> Void)?) UIView.animate(withDuration: 0.25) { // doSomething() about animations } completion: { finished in // doSomething() } // SwiftUI Button Button { } label: { }
-
상수를 정의할 때에는
enum
를 만들어 비슷한 상수끼리 모아둡니다. 재사용성과 유지보수 측면에서 큰 향상을 가져옵니다.struct
대신enum
을 사용하는 이유는, 생성자가 제공되지 않는 자료형을 사용하기 위해서입니다. -
더이상 상속이 발생하지 않는 클래스는 항상
final
키워드로 선언합니다. -
프로토콜을 적용할 때에는 extension을 만들어서 관련된 메서드를 모아둡니다.
좋은 예
final class MyViewController: UIViewController { // ... } // MARK: UITableViewDataSource extension MyViewController: UITableViewDataSource { // ... } // MARK: UITableViewDelegate extension MyViewController: UITableViewDelegate { // ... }
나쁜 예
final class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { // ... }
[GitHub - StyleShare/swift-style-guide: StyleShare에서 작성한 Swift 한국어 스타일 가이드]
[GitHub - DeveloperAcademy-POSTECH/swift-style-guide: 아카데미에서 사용 하는 코딩 스타일 가이드 입니다.]