본문 바로가기

Swift

Swift - 옵셔널

처음 Swift를 접하며 눈에 들어온 낯선 단어가 Optional이었습니다.

Swift는 최고의 안정성을 지향하며 만들어진 언어이고 바로 그 지향점을 위해 Optional이 탄생했습니다.

우리는 Optional을 통해 null포인터로 인한 런타임 오류의 발생가능성을 미리 예방 할 수 있게 되었습니다.

 

Optional은 변수에 '?'를 붙임으로 사용 할 수 있습니다.

 

이렇게 ?를 붙인 Optional이 의미하는 바가 무엇이냐함은 바로, 특정 변수가 nil 상태를 가질 수 '있다/없다'를 나타내기 위함입니다.

 

?를 붙인 Optional 변수는 nil, 즉 아무 값도 할당 되지 않은 상태일 수도 있음을 표시합니다. 값이 있을 수도, 없을 수도 있다. Optional의 의미를 바로 여기서 찾을 수 있습니다.

 

일반 변수: nil값을 가질 수 없다. vs 옵셔널 변수: nil값을 가질 수 있다.

var foo: String? = nil	// 타입 오른쪽에 ?를 붙여서 optional 변수임을 표시하였습니다. 따라서 nil값을 할당할 수 있는 변수가 됩니다.



var bar: String? = "test" // 초기화시 nil이 아닌 값을 넣을 수도 있습니다.


var test: String = nil // 오류 발생!

 

값이 있을 수도 없을 수도 있는 Optional을 그대로 이용하는 예를 보겠습니다.

 

아래의 구조체는 예약을 받는데 사용할 예약 구조체입니다. 따라서 예약하는 사람의 이름(name)과 나이(age)를 필수 정보로 받기 위해 nil이 아닌 일반 변수를 사용했습니다.(반드시 값이 있어야함)

 

반면에 내국인인지 여부(isNative)는 알아도 되고 몰라도되는 정보로 판단하여 Optional 변수로 선언하였습니다.

 

따라서 구조체 인스턴스 생성시 일반변수인 name, age는 생성자에서 꼭 값을 부여해야하고 Optional 변수인 isNative 변수는 값을 넣어도 되고 않넣어도 됩니다.

 

아래는 isNative에 값을 넣지 않아 인스턴스를 출력할 때 isNative가 nil 상태임을 확인 할 수 있습니다.

struct Reservation {
    
    var name: String
    var age: Int
    var isNative: Bool?
}

let myReservation = Reservation(name: "kim", age: 27) // 일반변수인 name과 age는 꼭 값을 부여해야 인스턴스 생성 가능!
print(myReservation)

//아래와 같이 출력됨. isNative 변수가 nil 상태임을 알 수 있다.
//Reservation(name: "kim", age: 27, isNative: nil)

 

 

 

옵셔널과 관련된 연산자

-옵셔널 연산자(?) : 특정한 데이터타입이 옵셔널임을 표현할 때 사용.
-옵셔널 강제 추출 연산자(!) : 옵셔널 형태의 값을 강제로 추출한다.
-nil 병합 연산자(??): nil이 아니면 앞의 연산자 앞의 값을, nil이면 연산자 뒤의 값을 반환한다.

var foo: String? = nil // 옵셔널 연산자 ?을 데이터타입 뒤에 붙임으로 옵셔널임을 표현. 따라서 nil 입력 가능
foo = "hello"
print(foo) // Optional("hello)로 출력
print(foo!) // hello로 출력. optional 객체의 값을 강제로 추출한다.

var boo: String? = nil
print(boo ?? "boo is nil")

 

 

 

옵셔널 바인딩: Optional 값을 안전하게 추출하는 방법

var foo:String? = "variable"

// Optioanl 바인딩
// 임시 상수 생성
if let boo = foo {
	print("foo is not nil")
    print("we can use \(boo) in the {}")
} else {
	print("foo is nil")
}

// 임시 변수 생성
if var boo = foo {
	boo = "we can change the value"
} else {
	print("foo is nil")
}

 

여러 변수를 한꺼번에 바인딩하는 것도 가능합니다. 단, 바인딩하는 모든 값이 nil이 아니어야 if 바로 다음의 {}안의 코드가 실행됩니다.

var foo:String? = "one"
var boo:String? = "two"

if let tom = foo, let jerry = boo {
	print("foo and boo both have value") // foo, boo 모두 nil이 아니어야 실행됨!
} else {
	print("there is nil")
}