일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Swift 문법
- 코딩테스트
- Stride
- navigationcontroller
- 프로그래머스
- 문자열 반복
- randomElement
- lifecycle
- inout
- SwiftUI
- propertWrappers
- swift grammer
- IOS
- @State
- dismiss
- @Binding
- willset
- @main
- Swift
- 생명주기
- App구조
- 대소문자바꾸기
- 짝수의합
- 랜덤추출
- didset
- Swift문법
- LV0
- 야곰아카데미
- 공식문서
- Property Observer
- Today
- Total
miniworld
[Swift 문법] Swift 공식 문서 파헤치기 - 1 The Basics 본문
안녕하세요 miniworld의 티스토리입니다.
iOS 개발자가 되기 위한 첫 걸음으로 공식문서를 파헤쳐보려고 합니다.
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/thebasics
Documentation
docs.swift.org
The Basics
Swift는 iOS, macOS, watchOS 및 tvOS 앱 개발을 위한 프로그래밍 언어입니다. C 또는 Objective-C로 개발한 경험이 있다면 Swift의 많은 부분이 익숙할 것입니다.
Swift는 정수에 대한 Int, 부동 소수점 값에 대한 Double과 Float, 부울 값에 대한 Bool, 그리고 텍스트 데이터에 대한 String을 포함하여 모든 기본 C 및 Objective-C 타입에 대한 자체 버전을 제공합니다. Swift는 또한 Collection Types에서 설명한 Array, Set 및 Dictionary라는 세 가지 주요 컬렉션 타입의 강력한 버전을 제공합니다.
C와 마찬가지로 Swift는 값을 저장하고 식별 이름으로 참조하기 위해 변수를 사용합니다. Swift는 값이 변경될 수 없는 변수들도 많이 사용합니다. 이러한 변수들은 상수로 알려져 있으며, C의 상수보다 훨씬 강력합니다. Swift에서는 값이 변경되지 않아도 되는 경우에 코드를 안전하고 명확하게 만들기 위해 상수를 사용합니다.
익숙한 타입 외에도 Swift는 Objective-C에는 없는 튜플(tuple)과 같은 고급 타입을 소개합니다. 튜플을 사용하면 값의 그룹을 생성하고 전달할 수 있습니다. 튜플을 사용하여 함수에서 여러 값을 단일 복합 값으로 반환할 수 있습니다.
Swift는 또한 값의 부재를 처리하는 옵셔널(optional) 타입을 도입합니다. 옵셔널은 "값이 있고 그 값이 x와 같다" 또는 "값이 전혀 없다"라고 말합니다. 옵셔널은 Objective-C의 포인터에서 nil을 사용하는 것과 유사하지만, 클래스 뿐만 아니라 모든 타입에 사용할 수 있습니다. 옵셔널은 Objective-C의 nil 포인터보다 안전하고 표현력이 뛰어나며, Swift의 많은 강력한 기능의 핵심입니다.
Swift는 타입 안전한 언어이며, 이는 코드가 작동할 수 있는 값의 타입에 대해 명확하게 해주는 것을 의미합니다. 코드 일부가 String을 필요로 한다면, 타입 안전성은 실수로 Int를 전달하는 것을 방지합니다. 마찬가지로, 타입 안전성은 옵셔널이 아닌 String을 필요로 하는 코드에 실수로 옵셔널 String을 전달하는 것을 방지합니다. 타입 안전성은 개발 과정에서 가능한 한 일찍 에러를 발견하고 수정하는 데 도움이 됩니다.
상수와 변수
상수와 변수는 특정 타입의 값을 이름과 연결합니다. 상수의 값은 한 번 설정되면 변경할 수 없지만, 변수는 나중에 다른 값으로 설정할 수 있습니다.
상수와 변수의 선언
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
쉼표로 구분하여 한 줄에 여러 개의 상수나 변수를 선언할 수도 있습니다.
var x = 0.0, y = 0.0, z = 0.0
Note
만약 코드에서 값이 변하지 않는다면, 항상 let 키워드와 함께 상수로 선언해야 합니다.
변수는 값이 변경되어야 하는 경우에만 사용해야 합니다.
Type Annotations
상수나 변수를 선언할 때, 상수나 변수가 저장할 수 있는 값의 종류를 명확하게 하기 위해 타입 주석(type annotation)을 제공할 수 있습니다. 상수나 변수 이름 뒤에 콜론(:)을 놓고, 공백을 둔 다음 사용할 타입의 이름을 쓰는 방식으로 타입 주석을 작성할 수 있습니다.
var welcomeMessage: String
선언부의 콜론은 "...의 타입..."을 의미하므로, 위의 코드는 다음과 같이 읽을 수 있습니다:
"String 타입의 welcomeMessage라는 변수를 선언합니다."
이제 welcomeMessage 변수는 오류 없이 어떤 문자열 값을 할당할 수 있습니다.
welcomeMessage = "Hello"
한 줄에 여러 개의 관련 변수를 같은 타입으로 정의할 수 있습니다.
var red, green, blue: Double
Note
실제로 타입 주석을 작성해야 하는 경우는 드뭅니다. 상수나 변수가 정의될 때 초기값을 제공하면 대부분의 경우 Swift가 해당 상수나 변수에 사용될 타입을 거의 항상 추론할 수 있습니다. 이에 대한 설명은 "타입 안전성과 타입 추론" 에서 다루었습니다.
상수와 변수 이름 짓기
상수와 변수 이름에는 유니코드 문자를 포함하여 거의 모든 문자를 사용할 수 있습니다.
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
상수와 변수 이름에는 공백 문자, 수학 기호, 화살표, 프라이빗 사용자 정의 유니코드 스칼라 값, 선 및 상자 그리기 문자를 포함할 수 없습니다. 또한 숫자로 시작할 수는 없지만, 이름 내의 다른 위치에서는 숫자를 포함시킬 수 있습니다.
특정 타입의 상수나 변수를 선언한 후에는 동일한 이름으로 다시 선언하거나 다른 타입의 값을 저장하도록 변경할 수 없습니다. 또한 상수를 변수로, 변수를 상수로 변경할 수도 없습니다.
Note
예약된 Swift 키워드와 동일한 이름을 상수나 변수에 지정해야 하는 경우, 이름으로 사용할 때 키워드를 역따옴표(```)로 묶어야 합니다. 그러나 가능한 한 키워드를 이름으로 사용하는 것은 피하는 것이 좋습니다.
기존 변수의 값을 호환 가능한 다른 값으로 변경할 수 있습니다.
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
// friendlyWelcome은 이제 "Bonjour!"입니다.
변수와 달리, 한번 설정된 상수의 값은 변경할 수 없습니다. 변경하려고 시도하면 코드를 컴파일 할 때 오류가 납니다.
let languageName = "Swift"
languageName = "Swift++"
// 컴파일 오류: languageName은 변경할 수 없습니다.
상수와 변수 출력
상수나 변수의 현재 값을 출력하기 위해 print(_:separator:terminator:)함수를 사용할 수 있습니다.
print(friendlyWelcome)
// "Bonjour!"를 출력합니다.
print(:separator:terminator:) 함수는 하나 이상의 값을 적절한 출력으로 출력하는 전역 함수입니다. separator와 terminator 매개변수는 기본값을 가지고 있으므로 이 함수를 호출할 때 생략할 수 있습니다. 기본적으로 함수는 출력한 줄을 개행 문자로 종료합니다. 줄 바꿈 없이 값만 출력하려면 terminator로 빈 문자열을 전달하면 됩니다.
Swift는 문자열 내에서 상수나 변수의 이름을 플레이스홀더로 사용하고, Swift에게 해당 상수나 변수의 현재 값을 바꾸도록 요청하기 위해 문자열 보간(string interpolation)을 사용합니다. 이름을 괄호로 묶고, 여는 괄호 앞에 역슬래시로 이스케이프 합니다.
print("The current value of friendlyWelcome is \(friendlyWelcome)")
// "The current value of friendlyWelcome is Bonjour!"를 출력합니다.
Note
문자열 보간에 사용할 수 있는 모든 옵션은 문자열 보간을 참조하십시오.
Comments
코드에 비실행 가능한 텍스트를 포함하기 위해 주석을 사용할 수 있습니다. 주석은 Swift 컴파일러가 코드를 컴파일할 때 무시됩니다.
Swift에서의 주석은 C의 주석과 매우 유사합니다. 한 줄 주석은 두 개의 슬래시로 시작합니다.
// 이것은 주석입니다.
여러 줄 주석은 슬래시 다음에 별표(/*)로 시작하고, 별표 다음에 슬래시(*/)로 끝납니다.
/* 이것은 여러 줄 주석입니다.
여러 줄에 걸쳐 쓸 수 있습니다. */
C의 여러 줄 주석과는 달리, Swift의 여러 줄 주석은 다른 여러 줄 주석 내에 중첩될 수 있습니다. 첫 번째 여러 줄 주석 블록을 작성한 후 첫 번째 블록 내에서 두 번째 여러 줄 주석을 시작하여 중첩 주석을 작성할 수 있습니다. 그런 다음 두 번째 블록을 닫은 다음 첫 번째 블록을 닫습니다.
/* 이것은 첫 번째 여러 줄 주석의 시작입니다.
/* 이것은 두 번째 중첩된 여러 줄 주석입니다. */
이것은 첫 번째 여러 줄 주석의 끝입니다. */
중첩된 여러 줄 주석을 사용하면, 이미 여러 줄 주석을 포함한 코드라도 큰 코드 블록을 빠르고 쉽게 주석 처리 할 수 있습니다.
세미콜론
Swift언어에서는 다른 언어들과 달리 코드의 각 문장 뒤에 세미콜론(;)을 쓰지 않아도 되지만, 원한다면 사용할 수도 있습니다.
한 줄에 여러개의 독립적인 문장을 작성하려면 세미콜론이 필요합니다.
let cat = "🐱"; print(cat)
// Prints "🐱"
Integers
정수는 소수 부분이 없는 정수로 얘를 들어 42와 -23과 같은 값을 가집니다. 정수는 부호있는(양수, 0, 음수) 또는 부호 없는 (양수 또는 0) 형태로 나뉩니다.
Swift에서는 8, 16, 32, 64 비트 형식의 부호 있는 정수와 부호 없는 정수를 제공합니다. 이 정수형은 C와 비슷한 명명 규칙을 따릅니다. 즉 8비트 부호 없는 정수는 UInt8타입이며, 32비트 부호 있는 정수는 Int32 타입입니다. Swift의 모든 타입과 마찬가지로 이 정수형은 대문자로 된 이름을 가집니다.
Integer Bounds 정수 범위
각 정수형의 최소값과 최대값에는 min과 max 속성을 사용하여 접근할 수 있습니다.
let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
이 속성들의 값은 적절한 크기의 숫자 타입이며, 따라서 동일한 타입의 다른 값들과 함께 표현식에서 사용할 수 있습니다.
Int
대부분의 경우, 코드에서 사용할 정수의 특정 크기를 선택할 필요는 없습니다. Swift는 현재 플랫폼의 기본 워드 크기와 동일한 크기를 가지는 Int라는 추가 정수형을 제공합니다.
- 32비트 플랫폼에서 Int는 Int32와 같은 크기입니다.
- 64비트 플랫폼에서 Int는 Int64와 같은 크기입니다.
특정 크기의 정수와 작업할 필요가 없는 경우에는 항상 코드에서 Int를 사용하세요. 이는 코드 일관성과 상호 운용성을 돕습니다. 32비트 플랫폼에서도 Int는 -2,147,483,648에서 2,147,483,647까지의 모든 값을 저장할 수 있으며, 많은 정수 범위에 충분히 큽니다.
UInt
Swift는 현재 플랫폼의 기본 워드 크기와 동일한 크기를 가지는 부호 없는 정수형인 UInt도 제공합니다
- 32비트 플랫폼에서 UInt는 UInt32와 같은 크기입니다.
- 64비트 플랫폼에서 UInt는 UInt64와 같은 크기입니다.
Note
UInt는 특정 플랫폼의 기본 워드 크기와 동일한 크기를 가진 부호 없는 정수형이 필요한 경우에만 사용해야 합니다. 이러한 경우가 아니라면, 값이 음이 아닌 것으로 알려져 있더라도 Int가 선호됩니다. 정수 값에 일관된 Int 사용은 코드의 상호 운용성을 돕고, 서로 다른 숫자 타입 간의 변환 필요성을 피하며, 정수형 추론과 일치하도록 합니다. 이에 대해서는 타입 안전성과 타입 추론에서 설명된 내용과 일치합니다.
Floating-Point Numbers
부동 소수점 숫자는 소수 부분을 가진 숫자로, 3.14159, 0.1, -273.15와 같은 값을 가집니다.
부동 소수점 타입은 정수 타입보다 훨씬 넓은 범위의 값을 표현할 수 있으며, Int에 저장할 수 있는 것보다 훨씬 크거나 작은 숫자를 저장할 수 있습니다. Swift는 두 가지 부호 있는 부동 소수점 숫자 타입을 제공합니다.
- Double은 64비트 부동 소수점 숫자를 나타냅니다.
- Float은 32비트 부동 소수점 숫자를 나타냅니다.
Note
Double은 최소 15개의 소수 자릿수의 정밀도를 가지고 있으며, Float의 정밀도는 최소 6개의 소수 자릿수일 수 있습니다. 사용해야 할 적합한 부동 소수점 타입은 코드에서 작업해야 하는 값의 특성과 범위에 따라 다릅니다. 두 타입 중 어느 것이 적합한지에 따라서는 Double이 선호됩니다.
Type Safety and Type Inference
Swift는 타입 안전한 언어입니다. 타입 안전한 언어는 코드가 작동할 수 있는 값의 타입에 대해 명확하게 지정하도록 유도합니다. 코드의 일부분이 문자열을 요구한다면 실수로 정수를 전달할 수는 없습니다.
Swift는 타입 안전성을 위해 코드를 컴파일하는 동안 타입 체크를 수행하고, 일치하지 않는 타입을 에러로 표시합니다. 이는 개발 과정에서 가능한 한 빨리 에러를 감지하고 수정할 수 있도록 도와줍니다.
타입 체크는 서로 다른 타입의 값을 다룰 때 에러를 피할 수 있도록 도와줍니다. 하지만 이는 모든 상수와 변수의 타입을 명시해야 한다는 의미는 아닙니다. 원하는 값의 타입을 명시하지 않으면 Swift는 값 제공을 통해 자동으로 적절한 타입을 추론합니다. 타입 추론은 컴파일러가 코드를 컴파일하는 동안 특정 표현식의 타입을 자동으로 추론하는 것을 가능하게 합니다. 이를 위해 컴파일러는 제공하는 값만으로도 타입을 추론할 수 있습니다.
타입 추론 덕분에 Swift는 C나 Objective-C와 같은 언어보다 훨씬 적은 타입 선언이 필요합니다. 상수와 변수는 여전히 명시적으로 타입을 지정하지만, 그 중 일부 타입 지정 작업은 자동으로 수행됩니다.
타입 추론은 특히 초기값을 가진 상수나 변수를 선언할 때 유용합니다. 이는 상수나 변수를 선언하는 지점에서 리터럴 값을 할당함으로써 자주 사용됩니다. (리터럴 값은 소스 코드에 직접 나타나는 값으로, 아래 예시에서의 42나 3.14159과 같은 값들을 말합니다.)
예를 들어, 새로운 상수에 타입을 지정하지 않고 리터럴 42를 할당한다면, Swift는 정수 타입으로 추론합니다. 왜냐하면 정수처럼 보이는 숫자로 초기화했기 때문입니다.
let meaningOfLife = 42
// meaningOfLife is inferred to be of type Int
마찬가지로, 부동 소수점 리터럴에 타입을 지정하지 않으면 Swift는 Double을 생성하려고 한다고 추론합니다.
let pi = 3.14159
// pi is inferred to be of type Double
Swift는 부동소수점 숫자의 타입을 추론할 때 항상 Double을 선택합니다. Float 대신에 Double을 선택하는 것입니다.
만약 정수와 부동소수점 리터럴을 표현식에서 결합한다면, 문맥으로부터 Double 타입이 추론됩니다.
let anotherPi = 3 + 0.14159
// anotherPi is also inferred to be of type Double
숫자 3의 리터럴 값은 명시적으로 지정되지 않았으며, 그래서 부동소수점 리터럴이 덧셈의 일부로 존재하는 것을 통해 적절한 출력 타입인 Double이 추론됩니다.
Numeric Literals
정수 리터럴은 다음과 같이 작성할 수 있습니다
- 10진수 : 접두사 없이 일반적인 10진수로 표현합니다.
- 2진수 : '0b' 접두사를 사용하여 2진수로 표현합니다.
- 8진수 : '0o' 접두사를 사용하여 8진수로 표현합니다.
- 16진수 : '0x' 접두사를 사용하여 16진수로 표현합니다.
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
부동소수점 리터럴은 10진수 또는 16진수로 표현할 수 있습니다. 소수점 양쪽에 숫자(또는 16진수)가 있어야 합니다. 10진수 부동소수점은 대문자 또는 소문자 'e'로 표시되는 선택적인 지수를 가질 수 있으며, 16진수 부동소수점은 대문자 또는 소문자 'p'로 표시되는 지수가 반드시 있어야 합니다.
지수가 x인 10진수의 경우, 기저 숫자는 10ˣ 으로 곱해집니다.
- 1.25e2 means 1.25 x 10², or 125.0
- 1.25e-2 means 1.25 x 10⁻², or 0.0125
지수가 x인 16진수의 경우, 기저 숫자는 2ˣ 으로 곱해집니다
- 0xFp2 means 15 x 2², or 60.0.
- 0xFp-2 means 15 x 2⁻², or 3.75.
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
숫자 리터럴은 가독성을 높이기 위해 추가적인 포맷팅을 포함할 수 있습니다. 정수와 부동소수점 모두 추가적인 0으로 패딩을 넣거나 가독성을 돕기 위해 밑줄을 사용할 수 있습니다. 이러한 포맷팅은 리터럴의 기본 값에는 영향을 주지 않습니다.
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
Numeric Type Conversion
코드에서는 모든 일반적인 용도의 정수 상수와 변수에는 Int 타입을 사용하세요. 이는 음수가 아닌 것으로 알려진 경우에도 해당합니다. 일상적인 상황에서 기본 정수 타입을 사용하면 정수 상수와 변수가 코드 내에서 즉시 상호운용성을 갖게 되며, 정수 리터럴 값의 추론된 타입과 일치하게 됩니다.
다른 정수 타입은 특정 작업에 명시적으로 필요한 경우에만 사용하세요. 외부 소스로부터 크기가 명시적으로 지정된 데이터를 사용해야 하는 경우, 성능, 메모리 사용 또는 필요한 최적화를 위해 사용하는 경우에 해당합니다. 이러한 상황에서 명시적으로 크기가 지정된 타입을 사용하면, 우연한 값 오버플로우를 방지하고 사용되는 데이터의 성격을 암묵적으로 문서화하는 데 도움이 됩니다.
Integer Conversion
정수 상수나 변수에 저장할 수 있는 숫자의 범위는 각 숫자 타입마다 다릅니다. Int8 상수나 변수는 -128부터 127까지의 숫자를 저장할 수 있지만, UInt8 상수나 변수는 0부터 255까지의 숫자를 저장할 수 있습니다. 크기가 지정된 정수 타입의 상수나 변수로 저장할 수 없는 숫자는 코드를 컴파일할 때 오류로 보고됩니다.
let cannotBeNegative: UInt8 = -1
// UInt8 can't store negative numbers, and so this will report an error
let tooBig: Int8 = Int8.max + 1
// Int8 can't store a number larger than its maximum value,
// and so this will also report an error
각 숫자 타입은 다른 값 범위를 저장할 수 있기 때문에, 숫자 타입 변환은 경우별로 선택해야 합니다. 이 선택 방식은 숨겨진 변환 오류를 방지하고 코드에서 명시적으로 타입 변환 의도를 나타내는 데 도움이 됩니다.
특정한 숫자 타입을 다른 타입으로 변환하려면, 기존 값으로 원하는 타입의 새로운 숫자를 초기화합니다. 아래의 예시에서 상수 twoThousand는 UInt16 타입이고, 상수 onedms UInt8 타입입니다. 그들은 직접적으로 더해질 수 없습니다. 왜냐하면 타입이 서로 다르기 때문입니다. 대신, 이 예시에서는 UInt16(one)을 호출하여 값이 one으로 초기화된 새로운 UInt16을 만들고, 이 값을 원래 값의 자리에 사용합니다.
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
위 예시에서 UInt16 타입의 twoThousand와 UInt8 타입의 one을 직접 더할 수 없기 때문에 UInt16(one)을 호출하여 UInt16 타입의 새로운 값을 만들어 사용합니다. 이렇게 하면 변환된 값을 사용하여 twoThousand와 더할 수 있게 됩니다. 결과적으로 twoThousandAndOne은 이제 2001과 같은 값이 됩니다.
SomeType(ofInitialValue)는 Swift 타입의 이니셜라이저를 호출하고 초기값을 전달하는 기본적인 방법입니다. UInt16은 UInt8 값을 받아들이는 이니셜라이저를 내부적으로 가지고 있으므로, 기존의 UInt8에서 새로운 UInt16을 만드는 데 이 이니셜라이저가 사용됩니다. 그러나 여기에는 어떤 타입이든 전달할 수는 없습니다. UInt16이 이니셜라이저를 제공하는 타입이어야 합니다. 새로운 타입(자체 타입 정의 포함)을 허용하는 이니셜라이저를 제공하기 위해 기존 타입을 확장하는 방법은 Extensions에서 다루고 있습니다.
Integer and Floating-Point Conversion
정수와 부동소수점 숫자 타입 간의 변환은 명시적으로 이루어져야 합니다
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double
여기서 상수 three의 값을 사용하여 Double 타입의 새로운 값을 만들어 덧셈의 양쪽이 동일한 타입이 되도록 합니다. 이 변환 없이는 덧셈이 허용되지 않을 것입니다.
부동소수점에서 정수로의 변환도 명시적으로 이루어져야 합니다. 정수 타입은 Double이나 Float 값을 사용하여 초기화될 수 있습니다
let integerPi = Int(pi)
// integerPi equals 3, and is inferred to be of type Int
이와 같은 방식으로 새로운 정수 값을 초기화할 때에는 항상 부동소수점 값이 잘립니다. 즉 4.75는 4가 되고 -3.9는 -3이 됩니다.
Note
숫자 상수와 변수를 결합하는 규칙은 숫자 리터럴 규칙과 다릅니다. 숫자 리터럴은 그 자체로 명시적인 타입을 갖지 않습니다. 리터럴의 타입은 컴파일러가 해당 값을 평가하는 시점에서 추론됩니다.
숫자 리터럴을 결합할 때는 예를 들어 리터럴 값 3을 리터럴 값 0.14159에 직접 더할 수 있습니다. 이는 숫자 리터럴이 자체적으로 명시적인 타입을 갖지 않기 때문입니다. 타입은 컴파일러가 평가하는 시점에서 추론됩니다.
Type Aliases
Type Aliases는 기존 타입에 대한 대체 이름을 정의합니다. 키워드를 사용하여 정의할 수 있습니다.
Type Aliases는 기존 타입에 대해 상황에 맞는 더 적절한 이름으로 참고하고자 할 때 유용합니다. 예를 들어, 외부 소스에서 특정 크기의 데이터를 다룰 때 type aliases를 사용할 수 있습니다.
typealias AudioSample = UInt16
type alias를 정의하면, 원래의 이름을 사용할 수 있는 모든 곳에서 별칭을 사용할 수 있습니다.
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0
여기에서 'AudioSample'은 'UInt16'의 별칭으로 정의되어 있습니다. 별칭이기 때문에 'AudioSample.min'호출은 실제로 'UInt16.min'을 호출하며, 'maxAmplitudeFound' 변수에 초기 값으로 0을 제공합니다.
Booleans
Swift에는 Bool이라는 기본적인 부울 타입이 있습니다. 부울 값은 논리적인 값이라고 불리며, 참(true) 또는 거짓(false) 중 하나만 가능합니다. Swift는 true와 false라는 두 개의 부울 상수 값을 제공합니다
let orangesAreOrange = true
let turnipsAreDelicious = false
'orangeAreOrange'와 'turnipsAreDelicious'의 타입은 부울 리터럴 값으로 초기화되었기 때문에 Bool로 추론됩니다. 위의 Int와 Double과 마찬가지로, true 또는 false로 설정되는 경우에는 상수나 변수를 별도로 Bool로 선언할 필요가 없습니다. 타입 추론은 상수나 변수를 다른 타입으로 초기화할 때 Swift 코드를 더 간결하고 가독성 있게 만드는 데 도움이 됩니다.
부울 값은 특히 if 문과 같은 조건문을 사용할 때 유용합니다
if turnipsAreDelicious {
print("Mmm, tasty turnips!")
} else {
print("Eww, turnips are horrible.")
}
// Prints "Eww, turnips are horrible."
if문과 같은 조건문에 대해서는 Control Flow에서 다룹니다.
Swift의 타입 안정성은 부울을 위해 부울이 아닌 값의 대입을 방지합니다. 다음 예제는 컴파일 타임 에러를 보고합니다.
let i = 1
if i {
// this example will not compile, and will report an error
}
하지만 다음 예제는 유효합니다.
let i = 1
if i == 1 {
// this example will compile successfully
}
i == 1 비교의 결과는 Bool 타입이며, 이렇게 두 번째 예제는 타입 체크를 통과합니다. i == 1 과 같은 비교에 대해서는 Basic Operators에서 설명합니다.
Swift의 다른 타입 안정성 예제와 마찬가지로, 이 접근 방식은 우연한 오류를 피하고 특정 코드 부분의 의도가 항상 명확하게 유지되도록 합니다.
Tuples
튜플은 여러 값들을 단일 복합 값으로 그룹화합니다. 튜플 내의 값들은 어떤 타입이든 상관없으며, 서로 같은 타입일 필요도 없습니다.
이 예제에서는, (4,4 "Not Found")는 HTTP 상태 코드를 설명하는 튜플입니다. HTTP 상태 코드는 웹 서버가 웹 페이지를 요청할 때 반환하는 특별한 값입니다. 웹 페이지가 존재하지 않을 경우 404 Not Found 상태 코드가 반환됩니다.
let http404Error = (404, "Not Found")
// http404Error is of type (Int, String), and equals (404, "Not Found")
(404, "Not Found") 튜플은 Int와 String을 묶어 HTTP 상태 코드에 숫자와 사람이 읽을 수 있는 설명을 제공합니다. 이는 "타입이 (Int, String)인 튜플"로 설명될 수 있습니다.
어떤 순서의 타입 조합이든 튜플을 생성할 수 있으며, 원하는 만큼 많은 다른 타입을 포함할 수 있습니다. (Int, Int, Int) 또는 (String, Bool)과 같은 타입의 튜플을 가질 수 있습니다.
튜플의 내용을 개별적인 상수나 변수로 분해하여 일반적인 방식으로 접근할 수 있습니다
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// Prints "The status code is 404"
print("The status message is \(statusMessage)")
// Prints "The status message is Not Found"
튜플의 값 중 일부만 필요한 경우, 튜플을 분해할 때 언더바(_)을 사용하여 튜플의 일부를 무시할 수 있습니다
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"
또는, 인덱스 번호를 사용하여 튜플의 개별 요소 값을 엑세스할 수도 있습니다.( 인덱스는 0부터 시작)
print("The status code is \(http404Error.0)")
// Prints "The status code is 404"
print("The status message is \(http404Error.1)")
// Prints "The status message is Not Found"
튜플을 정의할 때 개별 요소에 이름을 지정할 수도 있습니다
let http200Status = (statusCode: 200, description: "OK")
요소에 이름을 지정한 경우, 해당 요소의 값을 접근할 때 요소 이름을 사용할 수 있습니다.
print("The status code is \(http200Status.statusCode)")
// Prints "The status code is 200"
print("The status message is \(http200Status.description)")
// Prints "The status message is OK"
튜플은 특히 함수의 반환 값으로 유용합니다. 웹 페이지를 가져오려고 시도하는 함수는 (Int, String) 튜플 타입을 반환하여 페이지 가져오기의 성공 또는 실패를 설명할 수 있습니다. 서로 다른 타입의 두 가지 명확한 값을 반환함으로써, 함수는 단일 타입의 단일 값만 반환할 수 있는 경우보다 더 유용한 정보를 제공합니다. 자세한 내용은 Functions with Multiple Return Values 을 참조하세요.
Note
튜플은 관련된 값들의 간단한 그룹으로 사용하기에 유용합니다. 그러나 복잡한 데이터 구조를 생성하기에는 적합하지 않습니다. 데이터 구조가 복잡할 가능성이 있다면, 튜플 대신 클래스 또는 구조체로 모델링 하는 것이 좋습니다. 자세한 내용은 Structures and Classes 를 참고하십시오.
Optionals
옵셔널은 값이 없을 수도 있는 상황에서 사용됩니다. 옵셔널은 두 가지 가능성을 나타냅니다
값이 있는 경우, 옵셔널을 언래핑하여 해당 값을 엑세스할 수 있습니다.
값이 전혀 없는 경우도 있을 수 있습니다.
Note
옵셔널 개념은 C나 Objective-C에는 존재하지 않습니다. Objective-C에서 가장 비슷한 개념은 객체가 아닌 경우에 메서드에서 nil을 반환할 수 있는 능력입니다. 이 경우 nil은 "유효한 객체가 없음"을 의미합니다. 그러나 이는 객체에 대해서만 작동하며, 구조체, 기본 C타입 또는 열거형 값에는 작동하지 않습니다. 이러한 타입의 경우, Objective-C 메서드는 일반적으로 값이 없음을 나타내기 위해 특별한 값(예: NSNotFound)을 반환합니다. 이 접근 방식은 메서드를 호출하는 쪽이 특별한 값을 테스트하고 이를 확인해야 한다는 가정을 전제로 합니다. Swift의 옵셔널은 특정 타입에 대한 값의 부재를 나타낼 수 있으므로 특별한 상수가 필요하지 않습니다.
아래 예제는 옵셔널을 사용하여 값이 없는 경우를 처리하는 방법을 보여줍니다. Swift의 Int 타입은 String 값을 Int 값으로 변환하는 이니셜라이저를 가지고 있습니다. 그러나 모든 문자열을 정수로 변환할 수 있는 것은 아닙니다. 문자열 "123"은 숫자 값 123으로 변환될 수 있지만, 문자열 "hello, world"는 변환할 수 있는 명확한 숫자 값이 없습니다.
아래 예제는 이니셜라이저를 사용하여 String을 Int로 변환하려고 시도합니다
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"
이니셜라이저는 실패할 수 있기 때문에, Int 대신 옵셔널 Int를 반환합니다. 옵셔널 Int는 Int?로 표기되며, Int가 아닌 옵셔널임을 나타냅니다. 물음표는 내부에 있는 값이 옵셔널임을 나타내며, 즉 어떤 Int값을 포함할 수도 있거나 전혀 값이 없을 수 있다는 의미입니다. (Bool 값이나 String 값과 다른 값은 포함할 수 없습니다. Int거나 아무 값도 아닌 둘 중 하나입니다.)
nil
nil은 특별한 값으로 옵셔널 변수를 값이 없는 상태로 설정할 때 사용됩니다.
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value
Note
nil은 옵셔널이 아닌 상수나 변수에서 사용할 수 없습니다. 코드에서 어떤 조건에서 값이 없는 상태와 작업해야 하는 상수나 변수가 있는 경우, 해당 타입의 옵션러 값으로 선언해야 합니다.
기본 값을 제공하지 않고 옵션러 변수를 정의하면, 변수는 자동으로 nil로 설정됩니다.
var surveyAnswer: String?
// surveyAnswer is automatically set to nil
Note
Swift의 nil은 Objective-C의 nil과 동일하지 않습니다. Objectibe-C에서의 nil은 존재하지 않는 객체를 가리키는 포인터입니다. Swift에서의 nil은 포인터가 아닌, 특정 타입의 값이 없음을 나타냅니다. 모든 타입의 옵셔널은 nil로 설정될 수 있으며, 객체 타입뿐만 아니라 모든 타입에 대해 사용할 수 있습니다.
If Statements and Forced Unwrapping
if문을 사용하여 옵셔널 값이 있는지 확인하기 위해서 옵셔널을 nil과 비교할 수 있습니다. 이 비교는 "같음" 연산자 (==) 또는 "같지 않음 연산자 (!=)를 사용하여 수행합니다.
옵셔널에 값이 있는 경우, nil과 "같지 않음"으로 간주됩니다.
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// Prints "convertedNumber contains some integer value."
옵셔널이 값이 있다고 확신한 후에는 옵션러 이름의 끝에 느낌표(!)를 추가하여 내부 값을 액세스 할 수 있습니다. 느낌표는 실제로 "이 옵셔널은 확실히 값을 가지고 있을 것이라고 알고 있으니 사용해주세요"라고 말하는 것과 같습니다. 이것은 옵셔널의 값에 대한 강제 언래핑이라고 합니다.
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
// Prints "convertedNumber has an integer value of 123."
if 문에 대해서는 Control Flow을 참고하세요.
Note
존재하지 않는 옵셔널 값을 사용하기 위해 !를 사용하면 런타임 오류가 발생합니다. 옵셔널 값을 강제 언래핑하기 전에 반드시 옵셔널이 nil이 아닌 값을 포함하는 지 확인해야 합니다.
Optional Binding
옵셔널 바인딩을 사용하여 옵셔널이 값을 포함하는지 확인하고, 그렇다면 해당 값을 임시 상수나 변수로 사용할 수 있습니다. 옵셔널 바인딩은 if와 while문과 함께 사용하여 옵셔널 내부의 값을 확인하고, 단일 동작의 일부로 상수나 변수로 추출하는 데에 사용될 수도 있습니다. if와 while 문에 대해서는 Control Flow 을 참고하세요.
다음과 같이 if 문에 대한 optional binding을 작성할 수 있습니다.
if let <#constantName#> = <#someOptional#> {
<#statements#>
}
Optionals 섹션에서 소개한 possibleNumber 예제를 강제 언래핑이 아닌 optional binding을 사용하여 다시 작성할 수 있습니다.
if let actualNumber = Int(possibleNumber) {
print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
print("The string \"\(possibleNumber)\" couldn't be converted to an integer")
}
// Prints "The string "123" has an integer value of 123"
이 코드는 다음과 같이 읽을 수 있습니다
"만약 Int(possibleNumber)에 의해 반환된 optional Int값이 있다면, actualNumber라는 새로운 상수에 optional에 포함된 값으로 설정합니다"
반환이 성공적인 경우, actualNumber 상수는 if 문의 첫 번째 브랜치 내에서 사용할 수 있게 됩니다. 이미 optional에 포함된 값으로 초기화되었으므로 값을 엑세스하기 위해 '!' 접미사를 사용하지 않습니다. 이 예제에서 actualNumber는 단순히 변환 결과를 출력하는 데 사용됩니다.
만약 옵셔널에 포함된 원본 상수나 변수를 값을 엑세스한 후에 참조할 필요가 없다면, 새로운 상수나 변수에 동일한 이름을 사용할 수 있습니다.
let myNumber = Int(possibleNumber)
// Here, myNumber is an optional integer
if let myNumber = myNumber {
// Here, myNumber is a non-optional integer
print("My number is \(myNumber)")
}
// Prints "My number is 123"
이 코드는 이전 예제와 마찬가지로 myNumber가 값을 포함하는 지 확인하는 것으로 시작합니다. 만약 myNumber가 값이 있다면, 새로운 상수인 myNumber의 값이 그 값으로 설정됩니다. if문의 본문 내에서 myNumber를 작성하면 해당 새로운 비- 옵셔널 상수를 참조합니다. if 문의 시작 전과 끝에서는 myNumber를 작성하면 옵셔널 정수 상수를 참조합니다.
이러한 유형의 코드는 매우 흔하므로, 옵셔널 값을 언래핑하기 위해 더 짧은 표기법을 사용할 수 있습니다. 언래핑할 상수나 변수의 이름만 작성하면 됩니다. 언래핑된 새로운 상수나 변수는 옵셔널 값과 동일한 이름을 암묵적으로 사용합니다.
if let myNumber {
print("My number is \(myNumber)")
}
// Prints "My number is 123"
옵셔널 바인딩에서는 상수와 변수를 모두 사용할 수 있습니다. 만약 if 문의 첫 번째 분기에서 myNumber의 값을 조작하고 싶다면, if var myNumber와 같이 작성할 수 있습니다. 그러면 옵셔널 안에 포함된 값이 상수 대신 변수로 사용할 수 있습니다. if 문의 본문 내에서 myNumber에 대한 변경은 원래의 옵셔널 상수나 변수에 적용되는 것이 아니라 해당 지역 변수에만 적용됩니다.
쉼표로 구분하여 하나의 if 문에서 필요한 만큼 많은 옵셔널 바인딩과 부울 조건을 포함할 수 있습니다. 옵셔널 바인딩 중 하나라도 nil을 가지거나 어떤 부울 조건이 false를 평가하면, 전체 if 문의 조건은 false로 간주됩니다. 다음 if 문은 동등한 내용입니다.
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// Prints "4 < 42 < 100"
Note
if 문의 옵셔널 바인딩으로 생성된 상수와 변수는 if 문의 본문 내에서만 사용할 수 있습니다. 반면 guard 문으로 생성된 상수와 변수는 Early Exit에서 설명한대로 guard 문 다음의 코드 라인에서 사용할 수 있습니다.
Implicitly Unwrapped Optionals
앞에 설명한대로, 옵셔널은 상수나 변수가 "값이 없을 수도 있는" 상태임을 나타냅니다. 옵셔널은 값이 존재하는 지 확인하기 위해 if 문으로 확인하고, 값이 존재하는 경우에는 옵셔널 바인딩을 통해 값을 조건부로 추출할 수 있습니다.
가끔은 프로그램의 구조에서 옵셔널이 처음 값이 설정된 이후에 항상 값이 존재할 것이라는 것을 명확히 알 수 있습니다. 이러한 경우에는 옵셔널의 값이 접근될 때마다 확인과 추출을 하지 않아도 되므로, 이를 제거하는 것이 유용합니다.
이러한 종류의 옵셔널을 암시적 추출 옵셔널이라고 정의합니다. 암시적 추출 옵셔널은 물음표(?) 대신에 느낌표(String!)를 타입 뒤에 붙여서 선언하는 것으로 표현됩니다. 사용할 때 옵셔널의 이름 뒤에 느낌표를 붙이는 대신, 선언할 때 옵셔널의 타입 뒤에 느낌표를 붙입니다.
암시적 추출 옵셔널은 내부적으로는 일반적인 옵셔널입니다. 하지만 옵셔널의 값이 처음에 설정된 후에는 항상 존재할 것으로 확신할 수 있는 경우에 사용됩니다. Swift에서 암시적 추출 옵셔널의 주요 사용 사례는 클래스 초기화 시에 설명된 것처럼 클래스 초기화 과정에서 사용됩니다.
암시적 추출 옵셔널은 내부적으로는 일반적인 옵셔널이지만, 값을 접근할 때마다 옵셔널 값을 추출할 필요 없이 일반 값처럼 사용할 수 있습니다. 다음 예제는 옵셔널 문자열과 암시적 추출 옵셔널 문자열이 값을 명시적으로 추출할 때 동작하는 방식의 차이를 보여줍니다.
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation point
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation point
암시적 추출 옵셔널은 필요한 경우 옵셔널을 강제로 추출할 수 있는 권한을 부여한다고 생각할 수 있습니다. 암시적 추출 옵셔널 값을 사용할 때, Swift는 먼저 일반적인 옵셔널 값으로 사용을 시도합니다. 그러나 옵셔널로 사용할 수 없는 경우 Swift는 값이 강제로 추출됩니다. 위의 코드에서, optional 값인 assumedString은 implicitString에 할당되기 전에 강제로 추출됩니다. 이는 implicitString이 명시적으로 옵셔널이 아닌 String 타입을 갖고 있기 때문입니다. 아래의 코드에서 optionalString은 명시적인 타입을 갖지 않아서 일반적인 옵셔널입니다.
let optionalString = assumedString
// The type of optionalString is "String?" and assumedString isn't force-unwrapped.
암시적 추출 옵셔널이 nil인 경우에 해당 옵셔널의 값을 엑세스하려고 하면, 런타임 오류가 발생합니다. 이 결과는 값이 없는 일반적인 옵셔널에 느낌표를 붙인 경우와 정확히 동일합니다.
일반적인 옵셔널을 확인하는 방법과 마찬가지로, 암시적 추출 옵셔널이 nil인지 확인할 수 있습니다.
if assumedString != nil {
print(assumedString!)
}
// Prints "An implicitly unwrapped optional string."
암시적 추출 옵셔널을 optional vinding과 함께 사용하여 값을 확인하고 추출하는 단일 문장으로 작성할 수도 있습니다
if let definiteString = assumedString {
print(definiteString)
}
// Prints "An implicitly unwrapped optional string."
Note
암시적 추출 옵셔널을 사용할 때는 변수가 나중에 nil이 될 가능성이 있는 경우에는 사용하지 않는 것이 좋습니다. 변수의 수명 동안 nil 값을 확인해야 하는 경우에는 항상 일반적인 옵셔널 타입을 사용하세요
Error Handling
오류 처리는 프로그램이 실행 중에 발생ㅇ할 수 있는 오류 조건에 대응하기 위해 사용됩니다.
옵셔널과 달리, 값의 존재 또는 부재를 사용하여 함수의 성공 또는 실패를 전달하는 데 사용하는 반면, 오류 처리는 실패의 근본 원인을 판별하고 필요한 경우 에러를 다른 부분으로 전파할 수 있도록 해줍니다.
함수가 에러 조건을 만나면, 에러를 던집니다. 그 함수를 호출한 곳에서는 에러를 잡아내고 적절하게 대응할 수 있습니다.
func canThrowAnError() throws {
// this function may or may not throw an error
}
함수가 에러를 던질 수 있다는 것을 나타내기 위해선, 선언 시 throws 키워드를 포함시킵니다. 에러를 던질 수 있는 함수를 호출할 때는 try키워드를 표현식 앞에 붙입니다.
Swift는 자동으로 에러를 현재 스코프 밖으로 전파하여, catch 절에 의해 처리될 때까지 전파됩니다.
do {
try canThrowAnError()
// no error was thrown
} catch {
// an error was thrown
}
do 문장은 새로운 포함 스코프를 생성하여 에러를 하나 이상의 catch 절로 전파할 수 있게 합니다
다음 예제는 에러 핸들링이 다양한 에러 조건에 대응하는 방법을 보여주는 예시입니다
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
이 예시에서 makeASandwich() 함수는 깨끗한 접시가 없거나 재료가 부족한 경우 에러를 던집니다. makeASandwich() 함수는 에러를 던질 수 있기 때문에 함수 호출은 try 표현식으로 래핑됩니다. 함수 호출을 do 문으로 래핑함으로써 던져진 어떤 에러든 제공된 catch 절로 전파됩니다.
에러가 던져지지 않으면 eatASandwich() 함수가 호출됩니다. 에러가 던져지고 그 에러가 SandwichError.outOfCleanDishes와 일치한다면 washDishes() 함수가 호출됩니다. 에러가 던져지고 그 에러가 SandwichError.missingIngredients와 일치한다면 catch 패턴으로 캡처한 연관 값인[String]을 가지고 buyGroceries(_:) 함수가 호출됩니다.
에러를 던지고, 잡고, 전파하는 것에 대한 자세한 내용은 에러 헨들링(Error Handling)에서 자세히 다루고 있습니다.
Assertions and Preconditions
assertion 과 precondition은 런타임에서 발생하는 체크입니다. 이들은 추가적인 코드를 실행하기 전에 필수적인 조건이 충족되었는 지 확인하기 위해 사용됩니다. assertion이나 precondition의 불리언 조건이 참으로 평가되면, 코드 실행은 평소대로 계속됩니다. 하지만 조건이 거짓으로 평가되면 프로그램의 현재 상태가 유효하지 않은 것이므로 코드 실행이 종료되고 앱이 종료됩니다.
assertion과 precondition을 사용하여 코딩하는 동안 가정하고 기대하는 것들로 표현함으로써, 개발 중에 실수와 잘못된 가정을 발견할 수 있습니다. assertion은 개발 중에 잘못된 가정과 오류를 찾는 데 도움을 주고, precondition은 프로덕션에서 문제를 감지하는 데 도움을 줍니다.
런타임에서 기대사항을 검증하는 것 외에도, assertion과 precondition은 코드 내에서 유용한 문서화의 역할을 합니다. 앞서 에러 핸들링에서 다룬 에러 조건과는 달리, assertion과 precondition은 복구 가능하거나 예상 가능한 에러에 사용되지 않습니다. 실패한 assertion 또는 precondition은 프로그램 상태가 유효하지 않음을 나타내므로, 실패한 assertion을 잡을수 있는 방법이 없습니다.
assertion과 달리 precondition을 사용하는 것은 코드를 유효한 상태로 설계하는 것을 대체하지 않습니다. 그러나 유효한 데이터와 상태를 강제하기 위해 이들을 사용하면, 프로그램이 유효하지 않은 상태를 감지하고 예측 가능한 방식으로 실행을 중단하여 디버깅을 더 쉽게 할 수 있습니다. 유효하지 않은 상태가 감지되면 실행을 즉시 중단하는 것은 해당 유효하지 않은 상태로 인한 문제를 제한하는 데 도움을 줍니다.
assertion과 preconditon의 차이점은 언제 체크되는 지에 있습니다. assertion은 디버그 빌드에서만 체크되지만, precondition은 디버그와 프로덕션 빌드 모두에서 체크됩니다. 프로덕션 빌드에서는 assertion 내부의 조건은 평가되지 않습니다. 이는 개발 과정에서 원하는 만큼의 assertion을 사용할 수 있고, 프로덕션에서는 성능에 영향을 미치지 않습니다.
Debugging with Assertions
assertion은 Swift 표준 라이브러리의 assert(::file:line:) 함수를 호출하여 작성합니다. 이 함수에는 true 또는 false로 평가되는 표현식과 조건의 결과가 false인 경우에 표시할 메시지를 전달합니다.
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 isn't >= 0.
이 예제에서, age >= 0가 true로 평가되면 코드 실행이 계속되고, 즉 age의 값이 음수가 아닌 경우입니다. 위의 코드에서처럼 age의 값이 음수인 경우 age >= 0는 false로 평가되며, assertion은 실패하고 응용프로그램이 종료됩니다.
assertion 메시지는 생략할 수도 있습니다. 예를 들어 조건을 문장으로 반복하는 경우에는 메시지를 생략할 수 있습니다.
assert(age >= 0)
만약 코드가 이미 조건을 확인하는 경우 , assertion 실패를 나타내기 위해 assertionFailure(_:file:line:) 함수를 사용합니다.
if age > 10 {
print("You can ride the roller-coaster or the ferris wheel.")
} else if age >= 0 {
print("You can ride the ferris wheel.")
} else {
assertionFailure("A person's age can't be less than zero.")
}
Enforcing Preconditions
precondition 함수는 코드의 실행이 계속되기 위해 조건이 반드시 참이어야 하는 경우에 사용합니다. 예를 들어, subscript가 범위를 벗어나지 않는지 확인하거나 함수에 유효한 값이 전달되었는 지 확인하는 경우에 precondition을 사용할 수 있습니다.
precondition(::file:line:) 함수를 호출하여 precondition을 작성합니다. 이 함수에는 true 또는 false로 평가되는 표현식과, 조건의 결과가 false인 경우 표시할 메시지를 전달합니다. 예를 들면 다음과 같습니다.
// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")
또한 preconditionsFailue(_:file:line:)함수를 호출하여 실패가 발생했음을 나타낼 수도 있습니다. 예를 들어, switch 문의 default case가 선택되었지만, 모든 유효한 입력 데이터가 switch의 다른 case 중 하나에서 처리되어야 하는 경우에 사용할 수 있습니다.
Note
옵티마이저 설정(-Ounchecked)에서는 precondition이 확인되지 않습니다. 컴파일러는 precondition이 항상 참이라고 가정하고 코드를 최적화 합니다. 그러나 fatalError(_:file:line:) 함수는 최적화 설정과 관계없이 항상 실행을 중단합니다.
프로토타이핑 및 초개 개발 단계에서 fatalError(_:file:line:) 함수를 사용하여 아직 구현되지 않은 기능에 대한 스텁을 생성할 수 있습니다. "Unimplemented"라는 스텁 구현으로 fatalError("Unimplemented")를 작성하는 방식입니다. assert 또는 precondition과 달리 fatal error는 최적화되지 않으므로 스텁 구현이 만나면 항상 실행이 중단되는 것을 보장할 수 있습니다.
'Swift > Swift Documents' 카테고리의 다른 글
[Swift 문법] Swift 공식 문서 파헤치기 - 2 Basic Operators (0) | 2023.06.28 |
---|