티스토리 뷰
안녕하세요. 반해원입니다.
스위프트 문법을 공부하면서 마주한 옵셔널이란 개념을 정리해보려 합니다.
Optional 옵셔널
옵셔널이란 선택적인 이란 의미를 가진 단어인데요.
말 그대로 값이 선택적으로 있을 수도 있고~ 없을 수도 있다~ 라는 개념이라고 합니다.
값이 있다는 것은 아래와 같이 50이라는 정수값을 가질 때뿐 아니라 0이라는 정수값을 가질 때도 포함입니다.
age
라는 변수가 0이라는 값을 갖고 있다고 해서 어 얘는 값이 없네! 가 아닙니다.
let age = 0
let height = 50
값이 없다는 것을 표현하려면 nil
을 사용할 수 있는 타입으로 타입으로 지정해줘야 합니다.
nil
은 값이 없음을 의미하는 특수한 값입니다.
아래와 같이 타입형 뒤에 ?
를 붙여서 변수를 선언하거나
nil을 대입하여 변수를 생성해주면 됩니다.
let age: Int?
let height: Int? = nil
이 옵셔널 변수의 값을 사용하려면 그냥 쓰면 안 되고 언래핑(unwrapping)하여 사용해야 합니다.
값이 없는 경우가 있을 수 있으니 연산이나 대입에 바로 쓰면 오류가 발생할 수 있기 때문입니다.
이런 경우엔 앱이 죽을 수도 있으니 주의해서 언래핑(해제 또는 추출..)을 꼭 해줘야 합니다.
이제 옵셔널 변수의 값을 가져오는 방법을 알아봅시다.
Forced-Optional Unwrapping
먼저 옵셔널 값을 강제로 해제하는 방법입니다.
옵셔널 타입 뒤에 !
만 붙여주면 옵셔널 객체가 해제되면서 내부에 저장된 값을 바로 꺼내 사용할 수 있습니다.
let age: Int? = 10
let height: Int? = nil
print(age!) // 10
print(height!) // 값이 없으므로 오류 발생!
가장 간단한 방법이지만 그만큼 위험성을 갖고 있는데,
만약 옵셔널 변수가 nil
을 갖고 있다면 런타임 오류가 발생되므로 조심해야 합니다.
강제 해제 전에 값이 nil인지 확인해 주면 더 안전하게 옵셔널 값을 꺼내 쓸 수 있겠죠?
if age != nil {
print(age) // Optional(10)
print(age!) // 10
}
Optional Binding
위에서 if 절에서 옵셔널 값이 값을 갖고 있는지 확인한 것처럼
if 조건문 내에서 옵셔널 값을 일반 변수에 대입하여 구문에서 사용하는 방식을 옵셔널 바인딩이라고 합니다.
var name: String? = "banbanhaewon"
if let userName = name {
print("사용자 이름: \(userName)") // 사용자 이름: banbanhaewon
} else {
print("바인딩 실패")
}
위와 유사하지만 강제 해제 연산자 !
를 이용하지 않아도 자연스럽게 옵셔널이 아닌 String 변수로 대입되어 사용될 수 있습니다.
if 구문 말고 guard 구문을 사용해서도 바인딩 처리를 해줄 수 있습니다.
var name: String? = "banbanhaewon"
guard let userName = name else {
print("바인딩 실패")
return
}
print("사용자 이름: \(userName)") // 사용자 이름: banbanhaewon
if 구문은 옵셔널 변수 대입 후 처리 결과에 따라 다른 처리를 위해 사용하고,
guard 구문은 옵셔널 바인딩에 실패하면 바로 return 해버리는 방법으로 사용되기 때문에 실행 흐름상 옵셔널 값을 해제 못하면 다음으로 진행되지 않는 경우에 사용해 주는 것이 좋습니다.
Optional Chaining
마지막으로 옵셔널 체이닝에 대해 알아봅시다.
let imagePaths = ["star": "/glyphs/star.png",
"portrait": "/images/content/portrait.jpg",
"spacer": "/images/shared/spacer.gif"]
if imagePaths["star"]?.hasSuffix(".png") {
print("The star image is in PNG format")
}
// The star image is in PNG format
위와 같이 imagePaths 에 이미지 이름과 파일 주소를 갖고 있는 딕셔너리를 선언하고
imagePaths 딕셔너리에서 star 라는 키에 해당하는 값이 .png로 끝나는지 if 구문에서 체크하여 출력하는 소스인데요.
여기서 잠깐! 딕셔너리에 키로 접근하면 그 결과값은 옵셔널 타입으로 반환됩니다.
딕셔너리에 키로 사용되는 값은 Hashable 프로토콜이 구현된 어느 자료형이나 들어갈 수 있다고 합니다. (요것도 나중에 정리해 보겠습니다. 일단은 이렇게만 알고!)
따라서 존재하지 않는 키를 사용하여 딕셔너리에 접근할 가능성이 있으니 결과적으로 옵셔널 타입으로 정의된 값을 반환합니다.
다시 옵셔널 체이닝으로 돌아와서...
if imagePaths["star"]?.hasSuffix(".png")
에서
imagePaths["star"] 가 nil이 아닌 값을 반환하는지 체크하고
nil 이 아닌 "/glyphs/star.png" 값을 갖고 있으므로 이 값이 hasSuffix(".png")을 만족하는지 체크합니다.
즉, 옵셔널 값 체크를 체인처럼 쭉 이어서 한다는 의미로 보면 될 것 같습니다.
이 예제 코드에서는 옵셔널 체크를 하나만 해줬지만 여러 프로퍼티나 메소드로 값을 옵셔널 여부를 체크할 때 사용하면 코드를 더 간결하게 짤 수 있습니다.
만약 nil 값이 중간에 있다면 if 구문을 만족 못하므로 else 구문으로 빠지게 되겠죠.
Nil-Coalescing Operator
진짜 마지막으로! Nil 병합 연산자 ??
에 대해 알아보고 끝내겠습니다.
옵셔널 변수에 nil 값이 할당되어 있을 때 디폴트값으로 처리할 값을 지정할 수 있습니다.
let heartPath = imagePaths["heart"] ?? "/images/default.png"
print(heartPath) // /images/default.png
앞에서 말한 것처럼 딕셔너리는 존재하지 않는 키를 사용해서도 접근이 가능합니다.
그래서 imagePaths에 존재하지 않는 heart라는 키를 사용해서 heartPath 변수를 할당하려 하는데
만약 heart키를 가진 딕셔너리 값이 없다면?? 기본값으로 /images/default.png 라는 값(이미지 경로)을 저장시킬 때 활용할 수 있습니다.
오류 날 가능성도 줄어들고~ 코드도 간결하게~ 옵셔널 값을 처리해 줄 수 있습니다.
let shapePath = imagePaths["cir"] ?? imagePaths["squ"] ?? defaultImagePath
print(shapePath) // /images/default.png
또한 하나가 아닌 여러개의 ??
연산자를 체이닝하여 사용도 가능합니다!
그럼 오늘은 여기까지 하겠습니다.
나중에 추가할 내용이 생기면 야금야금 추가하겠습니다.
안녕~
참고한 내용들!
Apple Developer https://developer.apple.com/documentation/swift/optional
이재은, 꼼꼼한 재은 씨의 스위프트 문법편 https://product.kyobobook.co.kr/detail/S000001891068
'Swift' 카테고리의 다른 글
[Swift] final 키워드 (0) | 2024.01.24 |
---|
- Total
- Today
- Yesterday
- GCD
- optional
- dependencymanager
- Constraints
- Swift
- xcode
- 연동
- AppDelegate
- Chrome
- Push
- Branch
- AppleDeveloperProgram
- 개발자도구
- Firebase
- Final
- GIT
- typora
- SPM
- gitignore
- Operation
- 콘솔
- cocoapods
- IOS
- markdowneditor
- AutoLayout
- github
- 테스트폰
- scenedelegate
- markdown
- ruby
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |