본 포스팅은 '스위프트 프로그래밍 (3판) - 야곰 저' 도서와 앨런 Swift 문법 마스터스쿨 강의를 통해 공부하며 정리하는 포스팅입니다.
혹시 틀린 부분이 있거나 질문이 있으시다면 언제든지 댓글 달아주시면 정말 감사하겠습니다 :)
1. 옵셔널
1) 옵셔널이란?
- 값이 '있을 수도, 없을 수도 있음'을 나타내는 표현으로, 데이터 타입 뒤에 물음표(?)를 붙여 표현함
- 변수를 선언은 했으나 값이 할당되지 않았을 때 접근할 경우 컴파일 에러가 발생하므로, 개발자의 실수로 인해 컴파일 에러가 발생할 가능성을 줄여주기 위해서 사용하는 개념
- 옵셔널은 기존 데이터 타입에 nil까지 더해 임시적으로 "값이 없을 수 있음"을 포장지로 한번 더 감싸는 것과 같다.
- 즉 옵셔널 타입과 옵셔널이 아닌 타입은 서로 아얘 다른 타입이다.
2) 옵셔널 변수의 선언 및 할당
var myName: String = "yuri"
myName = nil // 런타임 에러
var myName: String? = "yuri"
print(myName) // Optional("yuri")
myName = nil // 오류 X
print(myNameO) // nil
var myName: Optional<String>
var yuriName: String?
print(myName) //오류
print(yuriName) //nil
- Optional<T> 가 정식 표현이고, String? 이 축약한 표현법이나, String? 만 먼저 nil로 초기화해준다는 점에서 차이가 있다.
🚨 Swift에서의 nil과 다른 프로그래밍 언어에서의 null은 다르다.
Optional을 뜯어보면 제네릭이 적용된 열거형임을 확인할 수 있다.
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
public init(_ some: Wrapped)
- 즉 nil 이란 Optional.none 이라는 열거형 케이스와 같고, 그 자체로 메모리 공간에 값이 없음을 의미 하는 것이 아니다. 값이 없음(Null)을 한번 더 감싸서 출력했을 때 오류가 나지 않도록 방지함
-> 따라서 nil을 할당한 변수를 접근했을 때 에러가 나지 않는 것이 이 이유임
- nil: 안에 값이 없음을 나타내는 키워드이며 열거형 케이스와 같음 / null은 정말 메모리 공간에 값이 없음을 의미
2. 옵셔널 추출(Optional Unwrapping)
1) 강제 추출 (forced unwrapping)
- 가장 지양해야하는 방식
- 값이 nil이든 아니든 강제로 값을 꺼내오는 방식이기 때문에, nil이라면 런타임 오류가 발생하므로 지양하는 것이 좋음
- 옵셔널 값의 뒤에 느낌표(!) 를 붙임
var myName: String?= "yuri"
myName = nil
print(myName!) // 런타임 에러
2) ⭐ 옵셔널 바인딩 (if let, guard let)
- 가장 지향해야하는 방식
- 옵셔널에 값이 있는지 확인할 때 사용하며,
만약 옵셔널에 값이 있다면 옵셔널에서 추출한 값을 상수나 변수로 할당해서 옵셔널이 아닌 형태로 사용할 수 있도록 해주는 방법
var myName: String? = "yuri"
if let name = myName { //name : 임시상수이므로 블록 밖에서는 사용 불가
print("My name is \(name)")
} else {
print("myName == nil")
}
if var name = myName { //변수이므로 변경 가능
name = "yuri2"
} ...
- 한 번에 여러 옵셔널의 값을 추출할 수 있는데, 이 때 하나라도 값이 없다면 해당 블록의 명령문은 실행되지 않는다.
var myName: String? = "yuri"
var myName2: String? = "yuri2"
var myName3: String? = "yuri3"
if let name = myName, let name2 = myName2 { //name, name2 : 임시상수이므로 블록 밖에서는 사용 불가
print("My name is \(name) Your name is \(name2)")
} else {
print("myName == nil")
}
var myName: String? = "yuri"
var myName2: String? = nil
if let name = myName, let name2 = myName2 { //myName2가 nil 값이므로 해당 블록이 실행되지 않음
print("My name is \(name) Your name is \(name2)")
}
func doSomething(name: String?) {
guard let n = name else { return } // n이라는 상수에 name에 값이 있어서 벗겨내서 담을 수 있다면, 계속 진행 아니라면 return
// guard : 걸러내기 위한 문법 -> 만족하지 않으면 return
print(n)
}
💡 guard let vs if let
https://dvlpr-chan.tistory.com/12
해당 글 참고에 더해서 스스로 차이점을 정리해보면,
if let
변수를 임시변수로 사용하기 때문에 코드 블럭 외의 구역에서는 해당 변수를 사용할 수 없다.
else문이 필수는 아니다.
임시 상수나 변수에 값을 할당할 수 있는 경우에만 코드 블럭을 실행하겠다는 의미
guard let : 변수를 지역변수로 사용 가능해서, 코드 블럭 외의 구역에서도 사용할 수 있다.
else문이 필수적으로 필요하다.
else문 안에는 return, break, continue, throw 등의 제어문 전환 명령어가 들어가야한다.
임시 상수나 변수에 값을 할당할 수 있으면 코드 아래를 실행하고, 할당할 수 없다면 실행하지 않겠다는 의미
3) nil-coalescing (닐 코얼레싱)
옵셔널 표현식 ?? 표현식
- 만약 옵셔널 표현식의 값을 꺼내올 수 있다면 안의 값을 꺼내오고, 꺼내올 수 없다면(nil 이라면) 기본값을 표현식으로 지정
var myName: String? = "홍길동"
var userName = myName ?? "누구세요" // nil이 아니면 myName을 벗겨서 사용하고, 아니면 "누구세요" 사용
// userName = 홍길동
3. 옵셔널 응용
옵셔널 체이닝
- 옵셔널 타입으로 선언된 값에 접근하고자 할 때 사용하는 일련으 과정으로, 접근 연산자(.) 앞에 물음표(?)를 붙임
- 옵셔널 체이닝 과정에서 값 하나라도 nil을 리턴한다면, 그 뒤를 평가하지 않고 바로 nil을 리턴함
choco?.name
building?.room?.number
함수의 파라미터가 옵셔널일 때
- 파라미터가 옵셔널이라면 꼭 파라미터로 넘기지 않아도 가능하다. 파라미터로 넘기지 않으면 자동으로 nil로 초기화
func doSomePrint(with label: String, name: String? = nil) { // String? = nil
print("\(label): \(name)")
}
doSomePrint(with: "레이블", name: "스티브 잡스")
doSomePrint(with: "레이블", name: nil)
doSomePrint(with: "레이블") // 아규멘트 생략 가능
'🐦 Swift' 카테고리의 다른 글
[Swift] 연산자 (0) | 2023.05.13 |
---|---|
[Swift] 변수와 상수, 의미 있는 이름 (0) | 2023.05.09 |
[Swift] 함수 (0) | 2023.03.15 |
[Swift] 흐름제어 (0) | 2023.03.14 |
[Swift] 데이터 타입 기본 (0) | 2023.03.08 |