티스토리 뷰
Control Flow — The Swift Programming Language (Swift 5.5)
Control Flow Swift provides a variety of control flow statements. These include while loops to perform a task multiple times; if, guard, and switch statements to execute different branches of code based on certain conditions; and statements such as break a
docs.swift.org
1차 수정 (2022 / 02 / 26) : 의역, 오타 및 스타일 수정
Control Flow(제어 흐름)
제어 흐름은 프로그램에서 실행되는 구문, 명령어, 함수가 호출되는 순서를 의미합니다.
Swift도 다른 프로그래밍 언어와 마찬가지로 다양한 제어 흐름 명령문을 제공합니다.
while, if, guard, switch, break, continue, for-in
for-in 루프를 통해 배열, 사전(dictionaries), 범위(range), 문자열 및 기타 순서(sequence)들을 쉽게 반복할 수 있습니다.
switch문은 많은 C 기반 언어에 비해 더 강력합니다. case 구문에 간격 일치, 튜플 및 특정유형을 캐스트 하여 다양한 패턴과 일치할 수 있습니다.
For-In Loops (for-in 루프)
for-in 루프는 배열, 숫자 범위, 문자열의 문자 등 순서를 반복하는 곳에 사용합니다.
아래 예는 배열의 문자열에 접근합니다.
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
// Hello, Anna!
// Hello, Alex!
// Hello, Brian!
// Hello, Jack!
사전(Dictionary) 을 반복하여 key-value 값에 접근할 수 있습니다. 사전이 반복될 때 각각의 항목은 (key, value) 튜플로 반환되며 튜플의 (key, value) 멤버들을 For-in 루프에서 임시 변수로 사용할 수 있습니다.
아래 예제 에서 튜플의 (key, value) 멤버들을 For-in 루프에서 명시적으로 사용한 (animalName, legCount) 에 넣어서 사용했습니다.
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
// cats have 4 legs
// ants have 6 legs
// spiders have 8 legs
Dictionary는 순서가 지정되어 있지 않으며, 반복할 때마다 순서가 보장되지 않습니다.
숫자 범위와 함께 for-in 루프를 사용할 수도 있습니다.
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
1...5 로 표현하면 1부터 5까지 5번을 반복합니다. 예제의 index는 for-in 루프 반복시 자동으로 설정되는 상수입니다. 암시적으로 선언되므로 let 키워드를 사용해 선언할 필요가 없습니다.
순서가 필요하지 않고 단순히 반복만을 원한다면 _ 를 사용할 수 있습니다.
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
print("\(base) to the power of \(power) is \(answer)")
// Prints "3 to the power of 10 is 59049"
3을 10번 곱하는 for-in 루프입니다. 따로 순서가 필요없어 _ 를 사용합니다. 1부터 power의 값인 10까지 10번을 반복합니다.
마지막 값을 포함하고 싶지않으면 ..< 를 사용하여 범위를 설정합니다.
let minutes = 60
for tickMark in 0..<minutes {
// 1분마다 render (60 번)
}
0부터 59 까지 총 60번을 반복합니다.
분(minute) 을 표현할 때 5분 마다 표현할 수도 있습니다. stride(from: to: by:) 를 사용하면 if문을 사용하지 않고 간단하게 작성할 수 있습니다. (열린 범위 = 마지막 숫자 미포함 입니다)
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// 0 부터 59까지 매 5분마다 render (0, 5, 10, 15 ... 45, 50, 55)
}
by 대신 through를 사용하면 닫힌 범위(맨 마지막 숫자 포함) 를 사용할 수 있습니다.
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
// 매 3시간 마다 render, 닫힌 범위 이므로 12 포함 (3, 6, 9, 12)
}
위 예제들은 for-in 루프를 사용해 범위, 배열, 사전, 문자열을 반복했다. 뿐만 아니라 Sequence 프로토콜을 준수하는 모든 collection 에 대해서도 사용할 수 있다.
While Loops
while 루프는 statements가 false가 될 때까지 루프를 수행합니다. while 루프는 루프를 돌기 전 반복하는 횟루를 알 수 없을 때 잘 사용됩니다. Swift에는 2가지 종류의 while 루프를 제공합니다.
- while : 루프가 시작할 때 마다 조건(condition) 확인
- repeat-while : 루프가 끝날 때 마다 조건(condition) 확인
while 루프의 일반 적인 형식은 다음과 같습니다
while 조건 {
코드
}
(Swift 공식문서의 예제는 너무 복잡하므로 간단한 예제를 만들어 보겠습니다)
var count = 0
while count < 5 {
print("\(count)")
count += 1
}
// 0
// 1
// 2
// 3
// 4
Repeat-While
Repeat While문은 블럭에 있는 것을 먼저 수행하고 그 다음 조건은 확인합니다. 조건이 false가 될 때 까지 반복합니다.
다른 언어의 do-while 문과 유사합니다
repeat {
코드
} while 조건
아래 예제를 보면 count 5가 조건을 만족하지 않지만 repeat { } 안의 구문을 먼저 실행하기 때문에 count 가 출력됩니다.
var count = 5
repeat {
print("\(count)")
count += 1
} while count < 5
// 5
Conditional Statements (조건문)
종종 특정 조건에 따라 다른 코드 조각을 실행하는 것이 유용합니다. 오류가 발생할 때 추가 코드를 실행하거나, 값이 너무 높거나 낮을 때 메시지를 표시할 수 있습니다. 이렇게 하려면 코드의 일부를 조건부(conditional) 로 만듭니다.
Swift는 if 문과 switch문 두가지 방법을 제공합니다. 일반적으로 if 문을 사용해 하나의 조건을 평가합니다. switch 문은 가능한 순열이 여러 개인 더 복잡한 조건에 적합하며 패턴일치가 실행할 적절한 코드 브렌치를 선택할 때 유용합니다.
If
가장 간단한 형태로 단일(single) if 조건문이 있습니다. 조건이 true일 때만 실행됩니다.
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
}
// Prints "It's very cold. Consider wearing a scarf."
if문은 else 를 사용해서 조건이 false 일 때의 대안을 제공합니다.
temperatureInFahrenheit = 40
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
// Prints "It's not that cold. Wear a t-shirt."
temperatureInFahrenheit = 40 으로 32 보다 조건은 false 가 되고, else 문 이 실행됩니다.
else if 를 사용해서 if를 여러 번 사용할 수 있습니다.
temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
// Prints "It's really warm. Don't forget to wear sunscreen."
마지막 else 절은 선택사항이므로 필요하지 않다면 제외할 수 있습니다.
temperatureInFahrenheit = 72
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
}
조건이 모두 다 false 이므로 print 되지 않습니다.
Switch
switch 문은 값(value)를 고려하고 몇 가지 일치 가능한 패턴을 비교합니다. 그런 다음 성공적으로 일치하는 첫 번째 블록의 코드를 실행합니다. if 문을 여러 번 사용하는 것 대신 switch 문을 사용합니다.
가장 간단한 형태의 switch 문은 동일한 타입의 값을 하나 이상과 비교합니다.
switch 비교해야할 값 {
case 값1 :
비교해야할 값 = 값1 이면 해당 코드 실행
case 값2,
값3:
비교해야할 값 = 값2 or 값3 이면 해당 코드 실행
default:
비교해야할 값이 case 의 어디에도 해당하지 않으면 실행
}
if 문의 본문과 마찬가지로, 각각의 case 는 별도로 실행되는 코드 블럭입니다. switch문을 선택해야하는 점을 결정합니다. 이 절차는 비교해야하는 값이 switching 되는 것입니다.
모든 switch 문은 exhaustive(완전) 해야 합니다. 즉, 가능한 모든 값의 타입이 고려되어 switch의 case문 중 하나와 일치해야 합니다. case 에 해당하지 않는 경우 default 키워드를 사용해 처리할 수 있습니다.
let someCharacter: Character = "z"
switch someCharacter {
case "a":
print("The first letter of the alphabet")
case "z":
print("The last letter of the alphabet")
default:
print("Some other character")
}
// Prints "The last letter of the alphabet"
No Implicit Fallthorugh (암시적 폴스루 없음)
C 와 Objective-C 와는 다르게 Swift의 switch문은 기본적으로 조건이 만족하면 case의 아랫부분을 실행하지 않습니다. 대신에 Swift는 매칭이 된 첫번째 case 문이 완료되면 break 문 없이 종료합니다. 이렇게 때문에 C에서보다 안전하고 쉽게 사용할 수 있으며, 실수로 하나 이상의 조건을 실행하는 경우를 막아줍니다.
Swift에서는 break 문이 필수가 아니다. break 문을 사용하여 특정 case를 일치시키고 무시하거나 case가 실행되기 전에 일치하는 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")
}
// This will report a compile-time error.
case 문은 반드시 실행문이 있어야 합니다. 위의 예제는 case "a" 에 해당하는 실행문이 없기 때문에 컴파일 에러가 발생한다.
여러가지 조건을 같이 사용할 수 도 있습니다.
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// Prints "The letter A"
fallthorugh 를 흘러내리는 것 이라고 해석하면 이해하기 편합니다. break문이 없어도 암시적으로 아래로 흘러나가는 것을 막아줍니다.
Interval Matching (범위 매칭)
switch에 범위에 대해서도 case를 작성할 수 있습니다.
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// Prints "There are dozens of moons orbiting Saturn."
위의 예제에서 approximateCount는 62 로 12 ~ 100 사이에 속합니다. 그에 따라 naturalCount = dozens of 가 됩니다.
Tuples (튜플)
switch문에서 Tuple을 사용해서 여러 가지 값들을 사용할 수 있습니다. Tuple의 각각의 항목은 각각의 다른 조건에 의해 테스트 될 수 있습니다. 만약 항목에 _를 사용한다면 어떤 값이든 될 수 있다는 것 입니다.
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"
somePoint 튜플이 해당하는 case 는 case (-2...2, -2...2): 입니다. 그에 따라 inside the box 가 출력됩니다.
위의 예제에서 (0,0) 은 4가지 case에 모두 해당합니다. 복수의 case에 해당할 수 있지만 Swift에서는 첫 번째 case문만 실행하고 그 외 나머지 것들은 무시합니다.
let somePoint = (0, 0)
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 "(0, 0) is at the origin"
Value Bindings(값 바인딩)
switch의 case에서는 실행문에서 사용하기 위해 일시적인 변수와 상수를 선언해 사용할 수 있습니다. 이것은 value binding으로 불리는데, 변수와 상수가 일시적으로 실행문에 묶여(binding) 있기 때문입니다.
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"
위의 예제에서 let으로 x, y 를 선언해 주었습니다. case문에서 한 번 선언 된 변수는 다시 선언하지 않고 사용할 수 있습니다. default 케이스가 없는데 마지막 case let(x,y) 가 모든 경우의 수를 커버하므로 default 케이스를 사용하지 않아도 됩니다.
Where
switch 문에서 where 를 사용하여 추가적인 조건을 확인할 수 있다.
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"
위의 예제에서 case 문의 where 절에서 추가적인 조건을 확인한다. 위 예제도 마지막 case가 모든 경우를 커버하므로 default 케이스가 필요하지 않다.
Compound Cases(여러 개의 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"
Compound cases에는 Value Binding(값 바인딩)도 포함될 수 있습니다. (case 조건에서 값을 선언할 수 있다는 뜻)
Compound cases의 모든 패턴은 동일한 바인딩 값을 포함해야 하며, 각 바인딩은 복합 케이스의 모든 패턴에서 동일한 타입의 값을 얻어야 합니다.
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"
Control Transfer Statements
Control transfer Statements는 코드가 실행될 때 다른 코드로 명령을 줘서 실행되는 순서를 바꿉니다. Swift에는 5가지 Control transfer Statements가 있습니다.
- continue
- break
- fallthrough
- return
- throw
continue, break, fallthrough 는 아래에서 살펴볼 것이고 return 은 Function(함수) 에서, throw는 Propagating Errors Using Throwing Functions에서 살펴 볼 것입니다.
continue
continue 문은 루프에게 지금 하는 일은 멈추고 루프를 건너 뛴 다음, 다음 반복의 시작에서 다시 시작하라고 명령합니다.
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput {
if charactersToRemove.contains(character) {
continue
}
puzzleOutput.append(character)
}
print(puzzleOutput)
// Prints "grtmndsthnklk"
위의 예제를 보면 if 문을 만족하면 for 아래의 appen문을 실행하지 않고 다음 반복(iteration) 으로 넘어갑니다. 결과 값으로 charactersToRemove의 배열에 있는 값을 포함하고 있으면 puzzleOutput에 추가되지 않습니다.
Break
break 문은 전체 control flow 문을 즉시 종료시킵니다. 스위치 또는 루프 문을 다른 경우보다 일찍 종료하려는 경우 사용합니다.
Break in a Loop Statement
루프 문 안에서 break를 사용하면, 루프문은 즉시 종료되고 루프의 마지막 } 로 이동합니다. 현재 루프는 종료되고 더 이상 반복(iteration) 하지 않습니다.
Break in a Switch Statement
switch 문에서 break를 사용하면 swtich문은 즉시 종료되고, switch문의 마지막 } 으로 이동합니다. Swift의 swtich문은 반드시 실행문이 있어야 하는데, 실행시키지 않고 싶은 case가 있을 때 break 를 사용합니다.
Swift의 case 실행문에 주석을 사용하면 런타임 에러가 발생한다. 주석은 실행문이라 볼 수 없다.
let numberSymbol: Character = "三" // Chinese symbol for the number 3
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "١", "一", "๑":
possibleIntegerValue = 1
case "2", "٢", "二", "๒":
possibleIntegerValue = 2
case "3", "٣", "三", "๓":
possibleIntegerValue = 3
case "4", "٤", "四", "๔":
possibleIntegerValue = 4
default:
break
}
if let integerValue = possibleIntegerValue {
print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
print("An integer value couldn't be found for \(numberSymbol).")
}
// Prints "The integer value of 三 is 3."
위의 예제는 라틴, 아라비안, 중국, 타이 숫자를 case에 따라 나눕니다. default 값에 해당할 때 possibleIntegerValue에 아무것도 할당하고 싶지 않으므로 break를 사용한다. (아무것도 할당되지 않을 경우를 대비해 possibleIntegerValue 를 옵셔널로 선언하고 switch 문이 끝나면 언래핑 해준다.)
Fallthrough(폴스루 = 흘러내림)
Swift에서는, switch 문이 끝나도 다음 케이스로 흘러 들어가지 않습니다. 즉 첫 번째로 맞는 case의 실행문이 실행되고 switch 문의 실행이 완료됩니다. C의 경우 break 가 없다면 다음 코드를 확인합니다. Swift의 switch 문은 여러가지 case가 실행되는 실수를 막아줍니다.
만약 c언어 처럼 case에 해당되도 switch 문이 계속 실행되고 싶다면 fallthorugh 를 사용합니다.
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."
위의 예제에서 5는 case에 해당하지만 fallthrough 가 있기에 default의 실행문이 실행됩니다.
Labeled Statements
Swift에서는 반복문과 조건문을 다른 반복문과 조건문에 중첩해서 복잡한 흐름 제어 구조를 만들 수 있습니다. break를 사용해서 반복문과 조건문을 조기에 종료할 수 있습니다. 이런 경우 때때로 break로 종료할 반복문이나 조건문을 암시해주는 것이 유용합니다. 이를 만족시키기 위해 statement label을 사용합니다.
(Swift 공식문서의 예가 복잡해서 간단한 예를 작성했습니다.)
var date = 24
var time = 3
todayDate: while date < 25 {
if time >= 12 {
print("New Day!")
break todayDate
}
else {
time += 1
}
}
// print "New Day"
if 문의 조건을 만족하면 todayDate = while 문을 종료합니다.
Early Exit
if문 처럼 guard 문도 표현식의 Boolean 값에 따라 실행이 결정됩니다. guard를 사용해 반드시 true일 때만 실행 되어야하는 조건을 guard의 실행문에 작성합니다. if 문과 다르게 guard는 항상 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 문의 조건이 true 면, guard의 } 의 뒤에 있는 코드가 실행됩니다. guard 문에서도 옵셔널 바인딩을 사용해 변수와 상수를 선언할 수 있는데, 선언 후에는 guard 문 이 있는 코드 블럭에서 사용 가능합니다.
조건이 만족되지 않으면(false) else 문이 수행됩니다. else 문을 종료 하기 위해 return, break, continue, thorw를 사용하며 fatalError(_:file:line:) 처럼 리턴 되지 않는 함수나 메소드를 호출하기도 합니다.
guard문을 사용하는 것은 코드의 가독성을 높여준다. 이를 통해 일반적으로 실행되는 코드를 다른 블록에 래핑하지 않고 작성할 수 있으며, 위반된 요구 사항을 처리하는 코드를 요구 사항 옆에 유지할 수 있습니다.
Checking API Availability
Swift는 API 사용 가능성을 확인하도록 만들어져 지정된 배포 대상에서 사용할 수 없는 API를 실수로 사용하지 않게 해줍니다.
컴파일러는 SDK의 가용성 정보를 사용하여 코드에 사용되는 모든 API를 프로젝트에서 지정한 배포 대상에서 사용할 수 있는지 확인합니다. 사용할 수 없는 API를 사용하려고 하면 컴파일 시 Swift는 오류를 보고합니다.
사용하려는 API를 런타임에 사용할 수 있는지 여부에 따라 if 또는 guard 문의 가용성 조건을 사용하여 코드 블록을 조건부 실행합니다. 컴파일러는 해당 코드 블록의 API를 사용할 수 있는지 확인할 때 사용 가능한지 정보를 이용합니다.
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
}
위의 예제에서 if문의 조건에 따라 ios 10 이상, macOS 10.12 이상에서만 실행됩니다. 마지막 인수 *가 필요하며 다른 플랫폼에서는 if 문이 대상에 지정된 최소 배포 대상에서 실행됩니다.
iOS, macOS, watchOS, and tvOS 를 사용할 수 있습니다. iOS 8 또는 macOS 10.10과 같은 주요 버전 뿐만 아니라 iOS 11.2.6 및 macOS 10.13.3과 같은 상세 버전도 지정할 수 있습니다
'Swift > Swift 공식문서' 카테고리의 다른 글
[Swift] 공식문서 07 - Closures (클로저) (0) | 2021.10.13 |
---|---|
[Swift] 공식문서 06 - Functions (함수) (0) | 2021.10.11 |
[Swift] 공식문서 04 - Collection Types (컬렉션 타입) (0) | 2021.10.06 |
[Swift] 공식문서 03 - Strings and Characters (문자열과 문자) (0) | 2021.09.11 |
[Swift] 공식문서 02 - Basic Operators (기본 연산자) (0) | 2021.09.09 |
- Total
- Today
- Yesterday
- Swift
- 코딩테스트
- 날씨어플
- Combine
- Swift공식문서
- vapor
- 프로그래머스
- 부스트캠프iOS
- 필독서
- Swift DocC
- 디자인 패턴
- SwiftUI
- Swift문법
- swiftUI 기초
- 앱개발
- Swift 디자인 패턴
- 코딩
- 개발
- 부스트캠프
- 부스트캠프7기
- 책후기
- 애플
- ios
- UX
- todo앱
- 코딩 테스트
- 책리뷰
- TODO
- Swift 서버
- 책
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |