Optional 발표준비
- 이번 iOS 앱 개발자 워크숍에서 iOS관련 발표를 준비하게 되었는데
주제는 iOS 앱 개발에서 중요한 Optional에 대해 발표하기로 정했다.
Optional의 사전적 의미
Optional : 선택적인
- 한마디로 Swift문법 상에서 값이 있을 수도 있고 없을 수도 있다는 뜻이다.
문자열로 예를 들자면 "Swift" -> 값이 있다. "" -> 값이 없다?? "" 는 값이 없는게 아닌 빈 문자열이다. 문자열에서 값이 없다 -> nil --------------------------------------------------- 정수형에서도 똑같다. 12 -> 값이 있다. 0 -> 이 또한 값이 0이다. nil -> 값이 없다. 딕셔너리와 배열또한 비어있다고 값이 없는 것이 아닌 비어있는 배열,딕셔너리일 뿐이고 값이 없다는 nil이다.
nil
- 값이 없다. 라는 뜻
- 모든 변수에 사용할 수 있는것은 아니다.
1) var test: String = “테스트입니다” test = nil // 오류 --------------------------------------- 2) var opt: String? print(opt) // nil --------------------------------------- 3) var good: String? = "정상 작동" print(good) // 정상 작동 --------------------------------------- 4) let error: String = error print(error) // 오류
이 4가지 예제에는 무슨 차이가 있을까?
1) test 변수에 이미 "테스트입니다"라는 값을 가지고 있는데 이 문자열을 비울순 있어도 값이 없는 nil로 바꿀순 없다. 2) 변수 opt에 아무 값도 지정하지 않았을 때 ?를 붙여 Optional형으로 사용이 가능하다. 이 형태가 대표적인 Optional형이다. 3) 2번과 같이 String뒤에 ?를 붙여서 Optional형으로 지정했지만 값이 있다. 이 처럼 Optional이 꼭 값이 없는 것만을 지칭하는게 아니다. 4) String형으로 상수를 선언했지만 값이 문자형이 아니기 때문에 컴파일 오류가 난다.
Optional이란?
- Optional이란 앞서 살펴 보았던 예제들과 설명에서 보았듯이 값이 있을수도 없을수도 있는 변수 혹은 상수를 뜻한다.
- Optional에 초기 값을 지정하지 않는다면 기본 값(Default Value)은 nil이다.
var test: String? print(test) // nil ---------------------- let ex: Int? = 1 print(ex) // 1
var opt: String? print(opt) // nil opt = “Optional” print(opt) // Optional(“Optional”) 값이 Optional형태로 감싸져서 출력
표로 보면 그 구성을 더 이해하기가 쉽다.
⌈----> nil (값이 없음을 뜻함) Optional | ⌊----> 어떠한 값(String, Int, ...,)
Optional Binding(옵셔널 바인딩)이란?
- 옵셔널의 값을 가지고 오고싶을 때 사용한다.
- 옵셔널 바인딩은 옵셔널의 값이 존재하는지 검사를 하고 존재한다면 그 값을 다른 변수에 대입시켜준다.
- if let 또는 if var을 사용 한다.
- 옵셔널의 값을 벗겨서 값이 있다면 if문 안으로 들어가고 값이 nil이라면 그냥 통과한다.
Ex) if let opt = optBinding { print(opt) // optBinding의 값이 존재한다면 해당 값이 출력됩니다. } // optBinding의 값이 존재하지 않는다면 if문을 그냥 지나칩니다.
또한 if 문에서 , 로 구분하여 여러 옵셔널을 바인딩 할 수 있다.
이 곳에서 사용된 모든 옵셔널의 값이 존재해야 if문 안으로 진입한다.var optBinding: String? = "" var optName: String? = "유재우" if let opt = optBinding, name = optName { // opt와 name의 값이 존재 }
Tip: 코드가 너무 길 경우에는, 여러 줄에 걸쳐서 사용하는 것이 바람직하다.
var optBinding: String? = "" var optName: String? = "유재우" if let name = optName, let opt = optBinding { // name과 opt 값이 존재 } 참고로, 두 번째 let 부터는 생략이 가능하다.
- 옵셔널을 바인딩할 때 콤마(,)를 사용해서 조건도 함께 지정할 수 있다.
- 콤마(,) 이후의 조건절은 옵셔널 바인딩이 일어난 후에 실행된다. 즉, 옵셔널이 벗겨진 값을 가지고 조건을 검사하게 된다.
var optAge: Int? = 25 if let age = optAge, age >= 20 { // age의 값이 존재하고, 20 이상이다. }
Optional Chaining(옵셔널 체이닝)이란?
- 옵셔널 체이닝은 옵셔널의 속성에 접근할 때, 옵셔널 바인딩 과정을 ? 키워드로 줄여주는 역할을 한다.
이런식으로 글로만 보면 이해가 잘 되지않아 예제를 보면서 이해하자.
- 상황 설명
옵셔널로 선언된 어떠한 배열 baeyul이 있다.
이 배열이 비어있는지를 검사를 해야한다.
그러려면 우선 배열이 nil이 아닌지를 확인하고 비어있는지 확인을 해야한다.Ex) let baeyul: [String]? = [] // 옵셔널로 선언된 배열 생성 var binBaeyul = false if let baeyul = baeyul, baeyul.isEmpty { // 배열에 값이 있는지 확인 후에 baeyul이 비어있는지 확인한다. binBaeyul = true print(binBaeyul) // 비어있을 때 참으로 값을 출력 } else { binBaeyul = false print(binBaeyul) //비어있지않을 때 거짓으로 값을 출력 }
이렇게 길고 복잡한 코드를 옵셔널 체이닝을 사용한다면?
let binBaeyul = baeyul?.isEmpty == true
앞서 말했듯이 옵셔널 체이닝은 옵셔널의 속성에 접근할 때, 옵셔널 바인딩 과정을 ? 키워드로 줄여주는 역할을 한다.
baeyul의 배열이 비어있거나 nil이거나 요소가 있을 경우 3가지 경우를 살펴보자.
- baeyul이 nil인 경우
baeyul?.isEmpty -----/ baeyul? 까지 실행되고 'nil'을 반환
- baeyul이 빈 배열인 경우
baeyul?.isEmpty ---------------/ 끝까지 실행되고 'true'를 반환
- baeyul에 요소가 있는 경우
baeyul?.isEmpty ---------------/ 끝까지 실행되고 'false'를 반환
baeyul?.isEmpty의 결과로 나올 수 있는 값은 nil, true, false가 된다.
isEmpty의 반환값은 Bool인데, 옵셔널 체이닝으로 인해 Bool?을 반환하도록 바뀐 것이다.
따라서 값이 실제로 true인지를 확인하려면, == true를 해주어야 합니다.
강제 언래핑
- 옵셔널 타입으로 감싸져 있는 값을 "?", "!"를 사용하여 강제로 풀어주는 작업을 뜻한다.
Ex) var option: int? option = 25 print(option) -> Optional(25) print(option!) -> 25
? -> 자료형 뒤에
! -> 변수명 뒤에
- 강제 언래핑을 사용하려는 값이 nil값이 아니라는 전제에 사용해야 한다.
var option: int? option = 25 if option != nil { // 이런식으로 !를 사용할 때에 보험?을 들어야 한다. print(option!) } else { print("nil") }
- 가장 좋은 언래핑 방법은 옵셔널 바인딩이다.
Implicitly Unwrapped Optional(암묵적으로 벗겨진 옵셔널)
- 옵셔널을 정의할 때 ? 대신 !를 붙이면 ImplicitlyUnwrappedOptional이라는 옵셔널로 정의된다.
- 값이 있을 때
var name: String! = "유재우" print(name) // 유재우
- 값이 없을 때
var name: String! print(name) // 오류
- 잘못된 타입일 때
var age: Int! = "25" print(age) // 오류
- 암묵적으로 벗겨진 옵셔널(!)을 사용할 때에는 변수 혹은 상수의 값이 nil이 아닐 거라는 확신을 가졌을 때 사용하는 것이 좋다.
- 그래도 언래핑하려면 옵셔널 바인딩이나 옵셔널 체이닝 방법을 사용하는것이 가장 안전하고 좋은 방법이다.