프로그램을 작성하다보면 특정 조건에서 코드를 실행해야하거나 실행하지 말아야하는 상황이 생깁니다. 또 특정 명령어를 반복해서 실행해야하는 일도 발생합니다. 이럴 때 조건문과 반복문을 사용합니다.
스위프트의 흐름 제어 구문에서는 소괄호 ()
를 대부분 생략할 수 있습니다.
사용해도 무관하지만, 중괄호 {}
는 생략할 수 없습니다.
let first: Int = 5
let second: Int = 7
if first > second {
print("fisrt > second")
} else if first < second {
print("fisrt < second")
} else {
print("fisrt == second")
}
switch 입력 값 {
case 비교 값1:
실행구문
case 비교 값2:
실행구문
fallthrough
// 이번 case를 마치고 switch 구문을 탈출하지 않고 다음 케이스로 넘어감.
case 비교값 3, 비교값 4, 비교값 5: // 한번에 여러 값과 비교 할 수 있음.
실행구문
break
default: // 한정된 범위가 명확지 않다면 default는 필수
실행구문
}
typealias NameAge = (name: String, age: Int)
let tupleValue: NameAge = ("yagom", 99)
switch tupleValue {
case ("yagom", 50):
print("정확히 맞췄습니다!")
case ("yagom", _):
print("이름만 맞았습니다. 나이는 \(tupleValue.age)입니다.")
case (_, 99):
print("나이만 맞았습니다. 이름은 \(tupleValue.name)입니다.")
default:
print("누굴 찾나요?")
}
이렇게 와일드카드 식별자를 사용하면 무시된 값을 tupleValue.age와 같은 형식으로 직접 가져와야하는 불편함이 생깁니다.
typealias NameAge = (name: String, age: Int)
let tupleValue: NameAge = ("yagom", 99)
switch tupleValue {
case ("yagom", 50):
print("정확히 맞췄습니다!")
case ("yagom", let age):
print("이름만 맞았습니다. 나이는 \(age)입니다.")
case (let name, 99):
print("나이만 맞았습니다. 이름은 \(name)입니다.")
default:
print("누굴 찾나요?")
}
let을 붙인 값 바인딩을 사용하여 미리 지정된 조건 값을 제외한 다른 값을 실행문 안으로 가져올 수 있습니다.
let 직급: String = "사원"
let 연차: Int = 1
let 인턴인가: Bool = false
switch 직급 {
case "사원" where 인턴인가 == true:
print("인턴입니다")
case "사원" where 연차 < 2 && 인턴인가 == false:
print("신입사원입니다")
case "사원" where 연차 > 5:
print("연식 좀 된 사원입니다")
case "사원":
print("사원입니다")
case "대리":
print("대리입니다")
default:
print("사장입니까?")
}
enum school {
case primary, elementary, middle, high, college, university, grauate
}
let 최종학력: School = School.university
switch 최종학력 {
case .primary:
print("최종학력은 유치원입니다.")
case .elementary:
print("최종학력은 초등학교입니다.")
case .middle:
print("최종학력은 중학교입니다.")
case .high:
print("최종학력은 고등학교입니다.")
case .high:
print("최종학력은 대학(교)입니다.")
case .high:
print("최종학력은 대학원입니다.")
}
열거형과 같이 한정된 범위의 값을 입력 값으로 받게 될 때 값에 대응하는 각 case를 구현한다면 default를 구현하지 않아도 됩니다.
enum Menu {
case chicken
case pizza
}
let lunchMenu: Menu = .chicken
switch lunchMenu {
case .chicken:
print("반반 무많이")
case .pizza:
print("핫소스 많이 주세요")
case _: // case default: 와 같은 표현
print("오늘 메뉴가 뭐죠?")
}
Menu라는 열거형은 나중에 case를 추가할 것 같다는 예상이 됩니다. 그래서 switch 구문 마지막 case로 와일드카드 case를 미리 추가해뒀습니다.
그러면 나중에 Menu 열거형에 case를 추가해도 switch 구문에서 컴파일 오류가 발생하지 않을 것입니다.
그런데 만약 Menu 열거형에 새로운 case를 추가했다고 생각해봅시다.
깜빡하고 switch 구문의 내부 코드를 수정하지 않았다면 오히려 case _의 상황이 발생할 가능성이 생깁니다.
이런 문제를 방지하기 위해서 unknown
속성을 사용할 수 있습니다.
이렇게 unknown
속성을 부여하면 case _에서 경고가 발생합니다.
경고를 통해서 해당 switch 구문이 모든 case에 대응하지 않는다는 사실을 알 수 있습니다.
이렇게 논리적인 오류에 대해 도움을 받을 수 있는unknown
속성을 부여할 수 있는 case는 case _ 혹은 default case 뿐입니다. 도, unknown 속성을 부여한 case는 switch 구문의 가장 마지막 case로 작성해야 합니다.
스위프트의 조건문에는 guard 구문도 포함되지만 guard 구문은 빠른종료 (14장)에서 소개합니다.
for-in 반복 구문은 반복적인 데이터나 시퀀스를 다룰 때 많이 사용합니다.
for 임시 상수 in 시퀀스 아이템 {
실행 코드
}
for i in 0...2 {
print(i)
}
// 0
// 1
// 2
for i in 0...5 {
if i.isMultiple(of: 2) {
print(i)
continue // 바로 다음 시퀀스로 건너뜀
}
print("\(i) == 홀수")
}
// 0
// 1 == 홀수
// 2
// 3 == 홀수
// 4
// 5 == 홀수
let helloSwift: String = "Hello Swift!"
for char in helloSwift {
print(char)
}
var result: Int = `
// 시퀀스에 해당하는 값이 필요 없다면 와일드카드 식별자를 사용하면 됨
for _ in 1...3 {
result *= 10
}
print("10의 3제곱은 \(result)입니다.")
// 10의 3제곱은 1000입니다.
for-in 구문은 스위프트의 기본 컬렉션 타입에서도 유용하게 사용할 수 있습니다.
딕셔너리는 넘겨받는 값의 타입이 튜플로 지정되어 넘어옵니다.
let friends: [String: Int] = ["Jay": 35, "Joe": 29, "Jenny": 31]
for tuple in friends {
print(tuple)
}
// (key: "Jay", value: 35)
// (key: "Joe", value: 29)
// (key: "Jenny", value: 31)
let 주소: [String: String] = ["도": "충청북도", "시군구": "청주시 청원구", "동읍면": "율량동"]
for (키, 값) in 주소 {
print("\(키) : \(값)")
}
// 시군구 : 청주시 청원구
// 도 : 충청북도
// 동읍면 : 율량동
let 지역번호: Set<String> = ["02", "031", "032", "033", "041", "042", "043", "051", "052", "053", "054", "055", "061", "062", "063", "064"]
for 번호 in 지역번호 {
print(번호)
}
// 02
// 031
// 032
// ...
특정 조건(Bool 타입)이 성립하는 한 블록 내부의 코드를 반복해서 실행합니다.
var names: [String] = ["Joker", "Jenny", "Nova", "yagom"]
while names.isEmpty == false {
print("Good bye \(names.removeFirst())")
}
// Good bye Joker
// Good bye Jenny
// Good bye Nova
// Good bye yagom
repeat 블록의 코드를 최초 1회 실행한 후, while 다음의 조건이 성립하면 블록 내부의 코드를 반복 실행합니다.
var names: [String] = ["Joker", "Jenny", "Nova", "yagom"]
repeat {
print("Good bye \(names.removeFirst())")
} while names.isEmpty == false
반복문을 작성하다 보면 종종 반복문을 중첩으로 작성하게 됩니다.
만복문 앞에 이름과 함께 콜론을 붙여 구문의 이름을 지정해주는 구문 이름표
를 사용하면 좋습니다. 이름이 지정된 구문을 제어하고자 할 때는 제어 키워드와 구문 이름을 함께 쓰면 됩니다.
var numbers: [Int] = [3, 2342, 6, 3252]
numbersLoop: for num in numbers {
if num > 5 || num < 1 {
continue numbersLoop
}
var count: Int = 0
printLoop: while true {
print(num)
count += 1
if count == num {
break printLoop
}
}
removeLoop: while true {
if numbers.first != num {
break numbersLoop
}
numbers.removeFirst()
}
}
// 3
// 3
// 3
/// numbers에는 [2342, 6, 3252]가 남습니다.