🐦 Swift

[Swift] 옵셔널, 옵셔널 바인딩, 강제 추출, nil-coalescing

dev_zoe 2023. 3. 20. 16:14
반응형

본 포스팅은 '스위프트 프로그래밍 (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

 

[Swift] if let vs guard let (기본편)

안녕하세요~ 차니에요! 오늘은 if let과 guard let의 특징과 사용법 그리고 차이점에 대해 알아보겠습니다! 1. Snippets Xcode Snippets을 활용해보도록 하겠습니다. Xcode 내에서 기본적으로 만들어져 있는

dvlpr-chan.tistory.com

해당 글 참고에 더해서 스스로 차이점을 정리해보면, 

 

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: "레이블") // 아규멘트 생략 가능

 

반응형