Swift 개발에 있어 범용적으로 사용할 수 있는 코드 컨벤션 가이드입니다
이 가이드는 코드의 일관성을 유지하고, 팀원 간의 협업을 원활하게 하기 위해 만들어졌습니다




기본 4 whiteSpace 들여쓰기 사용
Details
if exampleCode { // ... }
타입과 프로토콜의 이름에는 PascalCase를 사용하고, 그 외에는 lowerCamelCase를 사용하기
Details
protocolSpaceThing{ // ... }classSpaceFleet:SpaceThing{enumFormation{ // ... }classSpaceship{ // ... }varships:[Spaceship]=[]staticletworldName:String="Earth"func addShip(_ ship:Spaceship){ // ... }}letmyFleet=SpaceFleet()
@ViewBuilder메서드 경우 PascalCase 사용Details
@ViewBuilderprivatefunc ExampleComponent()->someView{...}
Bool 타입 변수 선언 시,
is||has로 시작 할 수 있도록 선언Details
varisShowing:Bool=false
동작을 의미하는 변수 및 메서드 선언 시, 동사가 맨 앞으로 오도록 선언
Details
enumAction{case showDialog ...}
API -
fetch, add, update, delete명칭 사용 ( not used - remove, get, create … )Details
func fetchList(){...}
extension 사용 시, 파일명
xxxxx +.swift
식별자 바로 뒤에 콜론(:)을 놓고 그 뒤에 공백을 두기
Details
varsomething:String="코드 컨벤션 만들기"func addWork(_ work:String){ // ... }
쉽게 추론할 수 있는 유형은 타입 표기 생략하기 ( 객체 생성 )
Details
// WRONG lethost:Host=Host() // RIGHT lethost=Host()
enumDirection{case left case right }func someDirection()->Direction{ // WRONG returnDirection.left // RIGHT return.left }
self.- 네이밍이 겹치지 않는 이상 사용하지 않기Details
finalclassListing{init(capacity:Int, allowsPets:Bool){ // WRONG self.capacity = capacity self.isFamilyFriendly = !allowsPets // `self.` not required here // RIGHT self.capacity = capacity isFamilyFriendly = !allowsPets }privateletisFamilyFriendly:Boolprivatevarcapacity:Intprivatefunc increaseCapacity(by amount:Int){ // WRONG self.capacity += amount // RIGHT capacity += amount // WRONG self.save() // RIGHT save()}}
여러 줄이 있는 배열은 각 괄호가 별도의 줄에 있도록 하기 ( 배열 속성 2개 이상의 경우 )
Details
// WRONG letrowContent=[listingUrgencyDatesRowContent(),listingUrgencyBookedRowContent(),listingUrgencyBookedShortRowContent()] // RIGHT letrowContent=[listingUrgencyDatesRowContent(),listingUrgencyBookedRowContent(),listingUrgencyBookedShortRowContent()]
guard let 구문 - else 문 클로저가 return 이 아닐 경우, 클로저 줄 내려서 사용 ( 조건 여러개는 당연히 조건에만 여러 줄 사용 )
Details
guardlet xxxx = xxxx else{return}guardlet xxxx = xxxx, xxxx.sdsda.isEmpty, xxxx.ssss.isEmpty else{return}guardlet xxxx = xxxx else{throw abcdError.aaaaa }
switch case 문은 각 case 별로 한줄씩 띄어서 사용
Details
func handle(_ action:SpaceshipAction){switch action {case.engageWarpDrive: warpDrive.engage()case.enableArtificialGravity: artificialGravityEngine.enable(strength:.oneG)case.scanPlanet(let planet): scanner.scan(planet)case.handleIncomingEnergyBlast: energyShields.engage()}}
한줄 주석과 여러줄 주석을 구분하기
Details
한줄 주석 // 여러줄 주석 ///
함수 정의에서 Void 리턴 타입을 생략하기
Details
// WRONG func doSomething()->Void{...} // RIGHT func doSomething(){...}
긴 함수의 호출 ( 파라미터 2개 이상 )
Details
// WRONG universe.generateStars(at: location, count:5, color: starColor, withAverageDistance:4) // WRONG universe.generateStars(at: location, count:5, color: starColor, withAverageDistance:4) // RIGHT universe.generateStars( at: location, count:5, color: starColor, withAverageDistance:4)
// RIGHT func generateStars( at location:Point, count:Int, color:StarColor, withAverageDistance averageDistance:Float)asyncthrows->String{populateUniverse()} // RIGHT func generateStars( at location:Point, count:Int, color:StarColor, withAverageDistance averageDistance:Float){populateUniverse()}
사용하지 않는 클로저 파라미터의 이름은 밑줄(
_)로 표시하기Details
// WRONG someAsyncThing(){ argument1, argument2, argument3 inprint(argument3)} // RIGHT someAsyncThing(){ _, _, argument3 inprint(argument3)}
중위 연산자는 양쪽에 공백이 하나씩 두기 및 다양한 공백 너비보다는 괄호를 사용하여 연산자가 많은 문을 시각적으로 그룹화하기
Details
// WRONG letcapacity=1+2letcapacity= currentCapacity ??0letmask=(UIAccessibilityTraitButton|UIAccessibilityTraitSelected)letcapacity=newCapacity letlatitude= region.center.latitude - region.span.latitudeDelta/2.0 // RIGHT letcapacity=1+2letcapacity= currentCapacity ??0letmask=(UIAccessibilityTraitButton | UIAccessibilityTraitSelected)letcapacity= newCapacity letlatitude= region.center.latitude -(region.span.latitudeDelta /2.0)
삼항 연산자의 표현이 너무 길어지면, 줄 내려서 사용하기
Details
letxx= ab ? a : b letdestinationPlanet= solarSystem.hasPlanetsInHabitableZone ? solarSystem.planetsInHabitableZone.first : solarSystem.uninhabitablePlanets.first
조건이 여러 개의 경우, 각 조건이 별도의 줄에 있도록 하기 ( 조건 2개 이상의 경우 )
Details
// WRONG if selectImage != userSaveImage && userNickname != nickname && userManager.uid !=""{ // ... } // RIGHT if selectImage != userSaveImage && userNickname != nickname && userManager.uid !=""{ // ... }
열거형에서
switch를 사용할 때defaultcase를 사용하지 말기Details
// WRONG switch trafficLight {case.greenLight: // Move your vehicle default: // Stop your vehicle } // RIGHT switch trafficLight {case.greenLight: // Move your vehicle case .yellowLight,.redLight: // Stop your vehicle }
기본 클래스는
finalDetails
// WRONG classSettingsRepository{ // ... } // RIGHT finalclassSettingsRepository{ // ... }
한줄일 경우엔
return생략Details
// WRONG ["1","2","3"].compactMap{returnInt($0)}varsize:CGSize{returnCGSize( width:100.0, height:100.0)}func makeInfoAlert(message:String)->UIAlertController{returnUIAlertController( title:"ℹ️ Info", message: message, preferredStyle:.alert)}var alertTitle:String{if issue.severity ==.critical {return"💥 Critical Error"}else{return"ℹ️ Info"}func type(of planet:Planet)->PlanetType{switch planet {case.mercury,.venus,.earth,.mars:return.terrestrial case.jupiter,.saturn,.uranus,.neptune:return.gasGiant }} // RIGHT ["1","2","3"].compactMap{Int($0)}varsize:CGSize{CGSize( width:100.0, height:100.0)}func makeInfoAlert(message:String)->UIAlertController{UIAlertController( title:"ℹ️ Info", message: message, preferredStyle:.alert)}var alertTitle:String{if issue.severity ==.critical {"💥 Critical Error"}else{"ℹ️ Info"}func type(of planet:Planet)->PlanetType{switch planet {case.mercury,.venus,.earth,.mars:.terrestrial case.jupiter,.saturn,.uranus,.neptune:.gasGiant }}
서로 다른 종류의 프로퍼티 선언 사이에 빈 줄을 추가하기
Details
// WRONG staticletgravityEarth:CGFloat=9.8staticletgravityMoon:CGFloat=1.6vargravity:CGFloat // RIGHT staticletgravityEarth:CGFloat=9.8staticletgravityMoon:CGFloat=1.6vargravity:CGFloat
import 문 관리
내부 / 외부 한 줄 띄고 관리 ( 외부를 상단에, 내부를 하단에, test 최하단 )
a-z 알파벳 순으로
Details
import Constellation import DLSPrimitives import Epoxy import Foundation @testableimport Epoxy
프로퍼티 순서
- 한줄 띄어서 구분
propertyWrapper가 붙는 프로퍼티를 최상단에 선언- EnvironmentObject, StateObject, ObservedObject, State, Binding, private 순으로 선언
- var / let 의 경우, var 를 상단에 let 을 하단에 선언
Details
structxxx{@EnvironmentObjectvar... @StateObject var... @ObservedObject var... @State var... @Binding var... @Presents var ppp:... private var...var aaa var bbb var ccc let ddd let eee }
- 연산 프로퍼티는 프로퍼티 중 맨 밑에 선언
Details
// WRONG varatmosphere:Atmosphere{ didSet {print("oh my god, the atmosphere changed")}}vargravity:CGFloat // RIGHT vargravity:CGFloatvaratmosphere:Atmosphere{ didSet {print("oh my god, the atmosphere changed")}}
In TCA
- @Dependency 위치는 Action 과 body 사이에 사용
- @Dependency 도 알파벳 순으로 선언
Details
enumAction{...}@Dependency(\.dismiss)vardismiss@Dependency(\.swiftDataService)varswiftDatavarbody:someReducerOf<Self>{
- 프로퍼티 && 액션
- 관련 기능끼리 모으는걸 우선시하고, 내부에서는 알파벳 순으로 정렬하기