swift 기초문법 - Optional(옵셔널) 정리하기

Swift의 큰 특징 중 하나라고 생각이 되는데요. 바로 Optional(옵셔널)입니다. 영어 의미로는 '선택적인' 이라는 뜻입니다. 어떤 의미일까요?

변수에 값이 있을 수도 있고, 없을 수도 있다 라는 것을 표현하기 위해서 사용합니다.

 

즉 '없는 것에 대해서 어떻게 표현을 할 것이냐.' 라는 개념입니다. swift에서는 nil이라는 값으로 없는 값을 표현하고 있으며, 값이 없는 경우를 나타내야 할 때에 optional을 사용하면 됩니다. 구글 번역기에서도 nil을 검색하면 '무'라는 의미로 나타납니다.

 

Optional은 언제 사용할 까?

var name: String = "minmong"
var petName: String = ""

그럼 Optional은 언제 사용을 해야 할까요? 예를 들어 보겠습니다. 저에 대한 데이터를 정의할 것인데요. 먼저 이름을 만들고, 반려 동물 이름도 만들었습니다. 하지만 저는 반려동물을 키우고 있지 않습니다. 그래서 petName을 ""으로 초기화를 해주었습니다. ""은 없는 값이 아닌 문자열이죠. 따라서 petName변수에는 값이 존재하고 있습니다. 그냥 의미 없는 문자열이 들어간 것일 뿐이죠. 앞에서 설명한 값이 없다는 것을 표현하지는 못하였습니다. 이럴 때 사용하는 것이 Optional입니다.

 

 Optional 변수 

var name: String = "minmong"
var petName: String? = nil	
//초기화를 따로 하지 않아도 optional을 사용하게 되면 nil로 초기화됩니다.

optional 변수는 타입에 ?를 붙여서 표현할 수 있습니다. 옵셔널변수는 따로 초기화하지 않아도 nil이 기본 값입니다. optional을 이용해서 petName이 없다는 것을 표현했습니다. 그러면 궁금한 점이 생겼습니다. 값이 있을 수도 있고, 없을 수도 있는데 해당 변수를 사용하면 어떻게 될까요?

 

TIP
 
 

Optional변수와 Optional이 아닌 변수는 다른 타입입니다.
Value of optional type 'String?' must be unwrapped to a value of type 'String'

 

 

optional 변수는 박스라고 생각하면 이해하기 쉽습니다. 박스에 아무것도 들어있지 않으면 빈 박스입니다. swift에서 표현을 하자면 nil로 표현이 됩니다. 반면에 박스 안에 15라는 값이 존재할 수 도 있습니다. 하지만 내가 필요한 값이 박스 안에 들어 있는 것이죠. 15를 박스 안에서 어떻게 꺼낼까요? 이 부분이 바로 optional 변수를 사용하는 부분입니다. 

어렸을 때 동전을 넣어서 하는 캡슐 뽑기 아시나요? 뽑기 구슬 나온 것을 깨부수면 안에 무언가 들어 있죠. 하지만 비어있는 것도 있었죠.

 

Forced unwrapping

박스(캡슐) 부시는 것을 unwrapping 언래핑이라고 부릅니다. 즉 forced unwrapping은 강제로 부시는 것을 말하는데요. 박스 안에 무엇이 있는지는 신경 쓰지 않습니다. 우선 깨부수어서 안에 있는 값을 가져온다는 것이죠.

var petName: String? = "코코"
print(petName)	//출력 : Optional("코코")

Optional 변수를 바로 사용할 경우 경고가 발생하는 걸 볼 수 있습니다. Fix의 방법으로 Force-unwrap이라는 부분이 있는데요. 이것이 강제로 부시는 방법입니다.

 

var petName: String? = "코코"
print(petName!) //출력 : 코코

Optional 변수뒤에 !를 붙이게 되면 강제로 박스를 부시는 의미입니다. petName이라는 박스를 부시고 안에 들어있는 "코코" 값을 꺼낼 수 있게 되는 것입니다. 하지만 Optional은 값이 없을 수도 있겠죠? 강제로 부셨는데 아무것도 없는 nil이 있다면 어떻게 될까요?

 

var petName: String?
print(petName!)

저는 앞에서 언급했듯이 반려동물이 없다고 했습니다. petName박스에는 nil이 들어있겠죠. 박스를 부셔서 nil을 꺼냈고 nil에 접근하여 print를 하려고 합니다. 바로 에러가 발생하는 걸 볼 수 있습니다.

error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
Fatal error: Unexpectedly found nil while unwrapping an Optional value

예기치 않게 nil이 발견되었다고 하네요. 당연히 없는 값에 접근을 하니 에러가 발생했습니다. 컴파일 단계에서는 박스에 어떤 값이 있는지 알지 못하기 때문에 실제로 코드가 런타임에 동작을 할 때에 박스를 강제로 부셔서 열어 보니 nil이 들어 있고 이것을 사용하면 문제가 발생하는 것이죠.

 

그래서 우리는 nil이 아닌 것을 확인하고 값을 사용해야 합니다.

 

Optional Binding (옵셔널 바인딩)

앞에서 Forced unwrapping 의 경우 nil일 수도 있는 변수를 그냥 열어보았고, 안전하지 않다는 것을 앞에서 확인했습니다. Optional Binding은 박스 안을 살펴 본다라고 생각하면 됩니다. 박스를 부시기 전에 nil인지 혹은 값이 들어 있는지를 먼저 확인합니다.

 

var petName: String?
if let unwrappedPetName = petName {
    print(unwrappedPetName)
} else {
    print("Pet이 없어요")
}
출력 결과 : Pet이 없어요

코드를 보면 if let구문을 볼 수 있습니다. Optional Binding 선택적 바인딩입니다. 즉 nil이 아닌 값이 있을 때만 바인딩이 됩니다. 현재 petName은 비어져있는 nil 입니다. 따라서 위쪽코드의 출력결과는 else문으로 빠져 "pet이 없어요" 입니다.

 

var petName: String? = "코코"
if let unwrappedPetName = petName {
    print(unwrappedPetName)
} else {
    print("Pet이 없어요")
}
출력 결과 : 코코

이제 박스안에 "코코"라는 이름이 들어 있습니다. if let을 통해서 먼저 박스안의 값을 살펴 봅니다. nil이 아니기 때문에 unwrappedPetName에 "코코" 문자열이 할당되며 출력 결과 코코가 print된 것을 확인 할 수 있습니다.

 

func printPetName(name: String?) {
   guard let petName = name else {
   print("반려동물부터 키워보는게 어때?")
   return
  }

  print(petName)
}

printPetName(name: nil)

출력 결과 : 반려동물부터 키워보는게 어때?

printPetName(name: "코코")

출력 결과 : 코코

다른 방법으로는 gurad문이 있습니다. 검사를 하여 다음 코드의 실행 유무를 결정할 때 사용할 수 있습니다. 옵셔널 name을 petName에 guard 문을 통해서 검사를 하게 됩니다. 만약 nil일 경우에는 else 구문으로 빠져서 코드를 수행하고 return 으로 함수를 빠져나가게 되는 것이죠. 만약 인자값으로 "코코"를 넣으면 어떻게 될까요? guard문을 통해서 nil이 아님을 확인 합니다. petName에 "코코"가 반환 되고 아래의 print(petName) 코드가 실행되게 됩니다.

 

C++ 을 사용할 때에 포인터가 nullptr인지 체크 하는것과 비슷하면서도 좀 다르다는 것을 느꼈습니다. '핵심은 유효한 값인지 확인한다.' 입니다. 

 

 

그리드형(광고전용)

이 글을 공유합시다

facebook twitter googleplus kakaoTalk kakaostory naver band

댓글

Designed by JB FACTORY