Swift는 여러가지 제어문이 존재함.
while은 작업을 여러 번 수행하기 위해,
if, guard, switch는 특정 조건에서 다른 코드를 실행하기 위해,
break, continue는 코드의 다른 포인트로 실행지점을 옮기기 위해,
for-in은 배열, 딕셔너리, 범위, 문자열, 다른 sequence를 훑어보기 쉽게 해 준다.
특히 switch문은 C와 비슷한 언어들에 비해 훠~~~~ㄹ씬 강력하다.
for-in으로 반복하는 반복문임. C의 for과 비슷하지만 문법이 조금 다르다.
배열을 순회할 때는 인덱스에 따라 나오지만,
딕셔너리를 순회하면 unordered이기 때문에 넣은 순서대로 나오는 것도 보장할 수 없고, 걍 지 맘대로 나올 수가 있다는 것을 유의!
stride를 통해 원하지 않는 순서는 스킵할 수 있다.
let minutes = 60
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
print(tickMark)
}
//(0, 5, 10, 15 ... 45, 50, 55) 출력됨
stride(from:through:by:) 를 사용하면 닫힌범위도 가능함.
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
// render the tick mark every 3 hours (3, 6, 9, 12)
}
모든 Collection에 사용할 수 있고, 내가 직접 만든 클래스나 collection 타입이 Sequence protocol을 만족한다면 for-in을 사용 가능하다.
while loop은 한 개의 조건을 검사하면서 돌아가는 반복문이다. 이 조건이 false일 때 종료됨.
var i = 0
repeat{
print("repeat \(i)")
i += 1
}while i<0
// repeat 0 출력.
조건문.
Swift에서 기본적으로 제공해 주는 code의 branch를 만들 수 있는 방법은
if와 switch임.
Every switch statement must be exhaustive.
이 말은 switch가 고려하는 모든 case들에 해당하는 동작이 있어야 한다는 것.
아니면 default 케이스로라도 묶어서 동작을 넣어줘야 한다.
C의 switch에서는 한 case가 끝나고 break를 넣어주지 않으면 바로 다음 case에 대해서 수행했지만(fall through the bottom of each case), Swift는 기본적으로 첫번째 matching case를 찾아 동작을 수행하고 바로 종료된다. break를 굳이 넣어주지 않아도 됨.
이로 인해 switch를 좀 더 안전하고 쉽게 사용할 수 있다.
또 각 case에는 최소한 하나의 실행 가능한 문장이 들어가 있어야 함.
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // Invalid, the case has an empty body
case "A":
print("The letter A")
default:
print("Not the letter A")
}
// "a" 케이스에 동작이 들어가 있지 않기 때문에 동작이 안된다.
튜플도 switch문에 집어넣을 수 있음.
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
// Prints "(1, 1) is inside the box"
_(wildcard pattern) 을 집어넣으면 아무 숫자나 들어가도 만족하는 것이다.
( _ , 0) 은 (0,0), (1,0),(4,0)등 첫번째에 아무거나 들어가도 되는 것.
값을 일시적인 상/변수에 저장해서 case문 body안에서 쓸 수 있다.
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// Prints "on the x-axis with an x value of 2"
where을 이용해서 switch에서 추가적인 조건을 붙일 수 있다.
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// Prints "(1, -1) is on the line x == -y"
여러 케이스에 동일한 동작을 넣고 싶을 때, compound case라는 걸 만들 수 있다.
그냥 case에 ,(콤마) 여러 개 쓰면 됨.
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) isn't a vowel or a consonant")
}
// Prints "e is a vowel"
//튜플도 여러 개 넣고, value binding도 가능함.
let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
print("On an axis, \(distance) from the origin")
default:
print("Not on an axis")
}
// Prints "On an axis, 9 from the origin"
코드의 다른 부분으로 제어를 넘기는 것들.
loop에서 지금 하는 작업을 멈추고 앞으로 돌아가서 이 루프의 다음 반복을 다시 실행하는 것.
실행을 즉시 끝냄. switch나 반복문 안에서 즉시 탈출하고 싶을 때 주로 사용함.
기본적으로 스위프트의 switch는 모든 케이스의 바닥까지 fall through하지 않는다.
C처럼 switch문 쓰고 싶으면 fallthrough 옵션을 넣으면 됨.
다음 케이스의 case를 검사하지 않고, 그 케이스의 statement를 실행할 뿐임.
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// Prints "The number 5 is a prime number, and also an integer."
중첩 제어문 같은 곳에서 원하는 곳으로 점프하고 싶을 때 사용한다.
점프하고 싶은 반복문이나 조건문의 앞에다가 라벨을 붙여주는 식으로 하면 되는데,
조건문에는 break를 사용할 수 있고, 반복문에는 break나 continue를 사용할 수 있다.
outSide: for i in 1...3 {
print("Outer Loop", i)
for j in 1...3 {
print(" inside", j)
break outSide
}
}
/*
outside 1
inside 1
*/
이런 식으로 쓸 수 있다.
for-in 루프에 outSide라는 라벨을 붙여 놓고, 안에 속해 있는 중첩반복문에서 break outSide를 호출해 바로 가장 바깥 반복문으로 나갈 수 있다.
아예 outSide 루프를 종료해 버림.
guard 는 if 와 비슷하지만, guard 조건이 참일 때 바로 뒤에 오는 구문이 실행되고, if와 달리 else가 필수적이다.
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(person: ["name": "John"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."
조건이 맞다면, guard문 다음 문장이 실행되고, 조건이 틀렸다면, else로 가서 코드가 실행된다.
이 else 안에서는 guard 코드블록을 빠져나갈 return, break, continue, throw 등 control transfer statement나 fatalError같은 반환값이 없는 메소드를 호출해야 한다.
guard를 사용하면 코드의 가독성을 높여주고, 요구 다음에 violated requirement를 처리하는 코드를 넣을 수 있다.
사용할 수 없는 API를 사용하려는 것을 막기 위해 API availability를 체크하는 기능이 있음.
내가 쓴 코드가 배포 대상자들이 사용할 수 있는 건지 확인해야 함.
사용 못하는 코드라면 runtime error가 나버림.
if #available(iOS 10, macOS 10.12, *) {
// Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
// Fall back to earlier iOS and macOS APIs
}
이런 식으로 iOS 10 이후, macOS 10.12 이후 버전에서 사용할 코드를 따로 써놓는다.
뒤에껀 좀 어려워서 나중에 다시 씀!