티스토리 뷰

iOS

[Swift] Optional

Sueaty 2021. 1. 12. 02:41

* 해당 글에는 개인 견해가 들어가있으므로 이곳을 참고하시면 조금 더 깔끔한 설명을 보실수도(?) 있습니다.

 

이 글은 Optional에 대해 다루겠습니다. 야곰님의 스위프트 프로그래밍 3판, The Swift Programming Language와 프로젝트 경험을 바탕으로 정리하는 글이라 오류가 있을 수 있습니다. 오류 발견 시 댓글로 꼭 말씀해주세요! 시작해볼까요?

Raywenderlich.com

Optional을 쓰려고 Notion을 딱 열었는데 문득 부스트캠프 당시 옵셔널을 '궁금증'이라고 부르던 캠퍼 분이 생각나서 혼자 ㅋㅋㅋ 거렸네요. 변수 뒤에 붙는 물음표 때문에 궁금증~ 궁금증~ 하셨는데 잘 지내시나요 동규님ㅋㅋㅋ(나 실명 언급해도 되는건가) Swift를 하면서 옵셔널을 모를 수는 없지만 면접 준비도 될 겸 깔끔하게 정리하고 싶어 기초 중의 기초를 가지고 나왔습니다.

Optional의 기본

public enum Optional<Wrapped>: ExpressibleByNilLiteral {
     case none	// abscence of value
     case some(Wrapped)	// presence of a value, stored as `Wrapped`
}

Optional은 변수나 상수 등에 값이 있음이 보장되지 않을 때 사용합니다. 열거형으로 정의되어 있는 optional은 none과 some 케이스를 갖는데 이 때 none이 값이 없음을 나타냅니다. 반대로 값이 있을 땐 some에 해당이 되지만 연관값 Wrapped에 할당되므로 래핑되어 있는 형상입니다.

래핑?

(상) Unwrapped (하) Wrapped

위는 옵셔널 변수를 강제 언래핑해서 프린트를 했고 밑에는 옵셔널 변수를 그대로 프린트 했습니다. 보면 Optional( )에 값이 들어가있습니다. 이것이 래핑된 것이죠. 이 값을 써먹기 위해서는 추출을 해야겠죠?

Optional 추출

옵셔널을 추출하는 방법은 3가지죠?

  • 강제 추출 → 회사에서 모든 책임을 질 자신이 있으면 쓰라고 배웠습니다만. 런타임 에러가 을마나 자주 발생하던지...
  • 옵셔널 바인딩 → 거의 이렇게 사용하죠?
  • 암시적 추출

Optional Binding

if나 while문과 결합하여 if/while문의 scope 내부에서 쓰일 상수나 변수에 값을 추출해 사용하는 방법입니다. 옵셔널 체이닝과 결합하여 쓰면 그 진가를 발휘한다~ 라고 써 있는 블로그들도 많았지만 개인적으로 많이 주르르르 이어지는 옵셔널 체이닝을 잘 활용하지는 않는 것 같습니다. 아 옵셔널 체이닝이란 옵셔널을 포함한 여러 값들을 이어서 필요한 property 또는 method에 접근하는 방식입니다. 가령 이런 것이죠.

let name: String? = school?.class.student?.name // 이름 property 접근

let numberOfClasses: Int? = school?.countNumberOfClassses() // method 접근

이런 옵셔널 체이닝과 옵셔널 바인딩을 결합하면 다음과 같이 쓸 수도 있습니다.

if let name: String = school?.class.student?.name {
   print(name)
}

위의 예시에서 school?.class.student?.name은 분명 옵셔널 값이었는데 이렇게 바인딩을 하면 값이 있을 경우에만 name에 값을 저장하고 if 문 안의 코드블럭들이 실행됩니다.

if let vs guard let

프로젝트를 하다보면 가끔 옵셔널을 추출할 때 if let 을 쓸 것인지 guard let을 쓸 것인지를 고민합니다. 저는 제 나름대로의 기준이 생겼지만 사용하시는 분들마다 다른 기준이 있을 수 있겠죠? 우선 그 차이를 알고 가보도록 하겠습니다.

guard let과 if let은 구조적인 측면에서 차이가 있습니다. guard문을 쓰게 되면 guard 코드 블럭 안에 예외사항들과 관련 된 코드를 작성하게 됩니다. 즉 추출한 값이 nil 값일 때 else문이 실행되는 것입니다. 그래서 guard let을 통해 추출한 값은 guard문 밖에서 사용되죠. 반면에 if let은 추출 값이 옵셔널이 아닐 경우에 실행할 코드들을 if문 내부에 쓰게 되죠. Dictionary에서 key 값을 사용해서 접근할 때 옵셔널로 반환이 되는 점을 사용해서 예시를 들어 보겠습니다.

let dict = [1: "a", 2: "b", 4: "d"]

// 방법 1
if let value = dict[3] {
   print(value)
} else {
   dict[3] = "c"
}

// 방법 2
guard let value = dict[3] else {
   dict[3] = "c"
   return
}
print(value)

제가 guard 문을 통해 옵셔널 추출을 할 때는 다음 중 하나에 해당하면 사용합니다.

1. 예외처리를 분명히 할 수 있을 때

2. 추출한 값이 계속 활용될 때

반대로 if 문을 통해 옵셔널 바인딩은 주로

1. 추출한 값을 가공을 통해 다른 형태로 저장만 하면 될 때. 즉, 뽑아낸 값을 이용하는 코드가 짧을 때 사용합니다.

 

 

Implicitly Unwrapped Optional

흔히 암시적 추출은 상수 및 변수가 nil 값으로 인해 런타임 에러가 발생하지 않는다는 확신이 있을 때 씁니다. 강제 추출처럼 위험한 방법이라 지양하는 것이 좋지만 우리가 흔히 암시적 추출을 사용하는 경우가 여럿 있습니다. 그 중 가장 쉽게 접할 수 있는 것은 바로 @IBOutlet. 물론 모든 IBOutlet이 암시적 추출을 사용하진 않습니다. 그러나 스토리보드에서 컨트롤+드래그를 통해 뷰컨트롤러에 끌어다 놓을 경우 자동적으로 @IBOutlet weak var startButton: UIButton! 이라는 코드를 생성해줍니다. 스토리보드에 해당 UIButton이 존재하니 nil 값이 아니라는 것이죠.

 

'iOS' 카테고리의 다른 글

[iOS] AppDelegate & SceneDelegate  (2) 2021.01.17
[iOS] SceneDelegate & AppDelegate의 역할  (0) 2021.01.16
[Swift] defer 구문  (0) 2021.01.16
[Swift] Optional  (0) 2021.01.12
[iOS] URLSession을 이용해 서버로부터 JSON 데이터 받아오기  (0) 2021.01.06
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함