[Swift] 스위프트 기초 - 흐름제어

koi·2022년 9월 28일
0
post-thumbnail

프로그램을 작성하다보면 특정 조건에서 코드를 실행해야하거나 실행하지 말아야하는 상황이 생깁니다. 또 특정 명령어를 반복해서 실행해야하는 일도 발생합니다. 이럴 때 조건문과 반복문을 사용합니다.

스위프트의 흐름 제어 구문에서는 소괄호 () 를 대부분 생략할 수 있습니다.
사용해도 무관하지만, 중괄호 {} 는 생략할 수 없습니다.

흐름제어

조건문

if 구문

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")
}
  • 스위프트의 if문은 조건의 값이 꼭 Bool 타입이어야 합니다.
  • else if는 몇개가 이어져도 상관없으며 else 블록은 없어도 상관없습니다.
  • if 뒤에 따라오는 조건수식의 소괄호는 생략할 수 있습니다.

switch 구문

switch 입력 값 {
	case 비교 값1:
    	실행구문
    case 비교 값2:
    	실행구문
        fallthrough
        // 이번 case를 마치고 switch 구문을 탈출하지 않고 다음 케이스로 넘어감.
    case 비교값 3, 비교값 4, 비교값 5: // 한번에 여러 값과 비교 할 수 있음.
    	실행구문
        break
    default: // 한정된 범위가 명확지 않다면 default는 필수
    	실행구문
}
  • 소괄호를 생략할 수 있습니다.
  • break 키워드 사용은 선택사항입니다.
    case 내부의 코드를 모두 실행하면 break 없이도 switch 구문이 종료됩니다
  • 비교값이 명확히 한정적인 값(열거형 등)이 아닐 때는 default를 꼭 작성해줘야 합니다.
  • 각 케이스에는 범위 연산자를 사용할 수 있습니다.
  • 케이스에 where 절을 사용하여 조건을 확장할 수도 있습니다.
  • 입력 값으로 숫자 표현이 아닌 문자, 문자열, 열거형, 튜플, 범위 패턴이 적용된 타입 등 다양한 타입의 값이 사용가능합니다.
  • case 다음으로는 꼭 실행가능한 코드가 위치해야 합니다.

와일드 카드 식별자를 사용한 튜플 switch case 구성

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을 붙인 값 바인딩을 사용하여 미리 지정된 조건 값을 제외한 다른 값을 실행문 안으로 가져올 수 있습니다.

where를 사용하며 switch case 확장

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("사장입니까?")
}

열거형을 입력값으로 받는 switch 구문

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 속성을 사용할 수 있습니다.

차후에 Menu 열거형에 추가한 case를 처리하지 않으면 경고를 내어줄 unkown 속성

이렇게 unknown 속성을 부여하면 case _에서 경고가 발생합니다.
경고를 통해서 해당 switch 구문이 모든 case에 대응하지 않는다는 사실을 알 수 있습니다.

이렇게 논리적인 오류에 대해 도움을 받을 수 있는unknown 속성을 부여할 수 있는 case는 case _ 혹은 default case 뿐입니다. 도, unknown 속성을 부여한 case는 switch 구문의 가장 마지막 case로 작성해야 합니다.

gaurd 구문

스위프트의 조건문에는 guard 구문도 포함되지만 guard 구문은 빠른종료 (14장)에서 소개합니다.

반복문

for - in 구문

for-in 반복 구문은 반복적인 데이터나 시퀀스를 다룰 때 많이 사용합니다.

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 반복 구문 사용

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

while 구문

특정 조건(Bool 타입)이 성립하는 한 블록 내부의 코드를 반복해서 실행합니다.

while 반복 구문의 사용

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

reqeat-while 구문

repeat 블록의 코드를 최초 1회 실행한 후, while 다음의 조건이 성립하면 블록 내부의 코드를 반복 실행합니다.

repeat-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]가 남습니다.
profile
Don't think, just do 🎸

0개의 댓글