옵셔널(Optional) 이란?
스위프트에서 옵셔널(Optional)은 값이 있을 수도 있고 없을 수도 있음을 나타내는 데이터 타입입니다.
먼저 스위프트에서 옵셔널이 존재하는 이유를 알아보자면 일반적인 프로그래밍 언어에서 null 또는 nil과 같은 값이 없는 변수에 접근하면 대부분 프로그램이 종료되거나 런타임 에러가 발생하는 문제를 방지하기 위해서입니다.
옵셔널을 선언해 봅시다.
타입 뒤에?를 붙이면 그 변수/상수가 옵셔널 타입이 됩니다.
var age: Int?
var name: String?
var height: Double?
var isStudent: Bool?
var scores: [Int]?
다양한 타입의 변수들을 옵셔널 타입으로 선언할 수 있습니다.
옵셔널 타입으로 선언된 변수들은 nil을 가질 수 있으므로, 안전하게 다루기 위해서는 옵셔널 바인딩 기법을 사용해야 합니다.
위 설명해서 nil이란 변수나 상수에 어떤 값도 없다는 것을 나타냅니다.
즉 옵셔널은 두 가지 상태를 가질 수 있다는 것입니다.
1. 값이 있는 경우(Wrapped Value) - 실제 값이 포함되어 있는 상태
2. 값이 없는 경우(Nil) - 값이 없는 상태
값이 있는 경우와 없는 경우를 코드로 나타내면 다음과 같습니다.
값이 있는 경우(Wrapped Value)
let age: Int? = 30 // 값이 있는 경우
print(age) // Optional(30)
값이 없는 경우(Nil)
let age: Int? // age는 nil
print(age) // nil
let age: Int? = nil// age는 Optional(nil)
print(age) // Optional(nil)
값이 없는 경우 내부에서도 두 가지 경우를 볼 수 있는데 초기값 지정 여부를 확인할 수 있습니다.
초기값을 지정하지 않아도 스위프트가 자동으로 nil을 출력하도록 처리하고 있습니다.
그렇다면 옵셔널로 묶인 값을 안전하게 사용해 봅시다.
옵셔널 바인딩(Optional Binding) 이란?
옵셔널 타입의 값을 안전하게 추출하고 사용하는 방법을 옵셔널 바인딩이라고 합니다.
옵셔널 바인딩을 사용하는 이유는 옵셔널 타입의 값을 안전하게 다루기 위해서이다. 강제 언래핑이나 옵셔널 체이닝 시 오류가 발생할 수 있으므로, 옵셔널 바인딩을 사용하는 것이 좋습니다.
옵셔널 바인딩에는 크게 두 가지 방식이 존재합니다.
1. if - let 구문을 사용한 옵셔널 바인딩
- if 블록 내에서만 언래핑된 값을 사용할 수 있고 내에서 언래핑된 값은 해당 블록 내에서만 볼 수 있고, 블록 밖에서는 사용할 수 없습니다.
2. guard - let 구문을 사용한 옵셔널 바인딩
- guard 블록 다음에 오는 함수 전체에서 언래핑된 값을 사용할 수 있습니다. 언래핑된 값은 함수 전체에서 사용할 수 있습니다.
먼저 if let 문의 기본 구조는 다음과 같습니다.
if let 상수 또는 변수 = 옵셔널 값 {
// 옵셔널 값이 nil이 아닌 경우 실행되는 코드 블록
} else {
// 옵셔널 값이 nil인 경우 실행되는 코드 블록
}
if let 문의 기본 구조를 바탕으로 작성한 코드입니다.
let name: String? = "hoon"
if let unwrappedName = name {
print("Unwrapped name: (unwrappedName)")
} else {
print("Name is nil.")
}
- let name: String? = "hoon" 은 옵셔널 String 타입의 상수 name을 선언하고 "hoon"을 저장합니다.
- if let unwrappedName = name { . . . } else { . . . } 구문은 name 옵셔널 값이 nil이 아닌 경우 unwrappedName에 그 값을 할당하고 if 블록 내부 코드를 실행합니다.
- 만약 name이 nil인 경우에는 else 블록 내부 코드가 실행됩니다.
- 이를 통해 옵셔널 값을 안전하게 추출하여 사용할 수 있게 됩니다.
다음은 guard let 문의 기본 구조입니다.
guard condition else {
// condition이 false인 경우 실행되는 코드 블록
return // 또는 throw, break 등
}
// condition이 true인 경우 실행되는 코드 블록
guard let 문의 기본 구조를 바탕으로 작성한 코드입니다.
func printName(name: String?) {
guard let unwrappedName = name else {
print("Name is nil.")
return
}
print("Unwrapped name: \(unwrappedName)")
}
let name: String? = "hoon"
printName(name: name)
- func printName(name: String?) 부분에서는 printName이라는 이름의 함수를 정의하고 있습니다. String? 타입의 name 파라미터를 받습니다.
- guard let unwrappedName = name else 구문을 통해 name 파라미터가 nil인지 확인합니다.
- name 파라미터가 nil이라며, "Name is nil." 메시지를 출력하고 함수를 종료합니다.
- name 파라미터가 nil이 아니라면 unwrappedName이라는 상수에 name의 값을 언래핑하여 저장합니다.
- print("Unwrapped name: \(unwrappedName)") 구문을 통해 언래핑된 name 값을 출력합니다.
- let name: String? = "hoon" 구문에서 name 변수를 "hoon"이라는 값으로 초기화하고 있습니다. 이 name 변수는 String? 타입의 옵셔널 값입니다.
- printName(name: name) 구문에서는 printName 함수를 호출하면서 name 변수를 인자로 전달합니다.
위 코드의 실행 결과는 Unwrapped name: hoon 이 출력 됩니다.
이는 name 변수가 "hoon"이라는 값을 가지고 있기 때문에, printName 함수 내부에서 unwrappedName에 성공적으로 값이 할당되었고, 그 값이 출력된 것을 확인할 수 있습니다.
잘못된 내용 혹은 오타가 있거나 더 좋은 내용 피드백은 언제나 환영입니다 :)
'Apple > Swift' 카테고리의 다른 글
[iOS/Swift] 저장 속성(Stored Property) 이란? (1/2) (0) | 2024.08.02 |
---|---|
[iOS/Swift] 값 형식(Value Types), 참조 형식(Reference Types) 이란? (0) | 2024.07.31 |
[iOS/Swift] 생성자(Constructor), 초기화(Initialization) 란? (0) | 2024.07.26 |
[iOS/Swift] 구조체(Struct), 클래스(class) 란? (0) | 2024.07.22 |
[iOS/Swift] 열거형(Enums) 이란? (2) | 2024.07.20 |