k-coding
Swift 옵셔널 (Optional) 본문
Swift 옵셔널 (Optional)
swift는 kotlin과 마찬가지로 null safe언어이다.
따라서 변수타입 옆에 ? 를 통하여 null값을 허용 할 수 있는데,
kotlin과의 차이점은 null이 아니라 nil을 사용한다는 것이다.
그냥 null을 swift에서는 nil로 사용한다고 생각하면 편하다.
예제 )
var name: String? = "choiKi"
name = nil
그런데 여기서 보통 nil이 언제 쓰일까라고 한다면
위에 말했듯이 Swift는 null safe 언어이다. 따라서 언어의 안전성과 관련이 있는데, 예시로 설명하자면
프로그램 가동중에 오류가 발생했을때 , 프로그램의 안전성에 의하여,
앱 가동은 중지되지 않지만 값을 nil값으로 반환해주어서 오류라는것을 알려준다.
예제 )
var list = ["name":"choiki","job":"student"]
let name = list["name"] // 문제 없음
let name2 = list["gender"] // 에러
위와 같은 상황에서 name2에서 꺼내오려는 gender라는 key값은 존재하지 않는다. 따라서 이러한 경우
swift언어에서는 name2값에 nil값을 반환해준다.
Non-Optional / Optional
Non Optional은 우리가 기본적으로 변수, 상수를 선언할 때 했던 기본적인 방식이다.
var name: String = "최기훈"
이러한 non optional은 무조건 초기값을 가져야만한다.
또한 이런 상태에서는 값을 nil로 지정할 수 없다.
Optional타입은 선언하는 두가지 방법이 존재하는데
첫째 Type Annotation 이용하기
let name: String?
둘째 Type Inference 이용하기
var name: String = nil
let yourName = name // nil
선언과 동시에 nil값으로 지정해주는 방법으로 yourName이 선언과 동시에 nil값이 되는 경우이다.
옵셔널의 타입
옵셔널로 지정하였으면 반드시 타입명을 지정해주어야 한다.
let abc = nil
다음과 같은코드에서 상수 abc의 타입은 아무리 swift라도 타입추론을 할 수가없다.
따라서 다음과 같이 타입은 반드시 지정해주어야한다.
let abc: Int? = nil
그렇다면 위와같은 코드의 타입을 출력하면 어떻게 나올까?
let abc:Int
let abcd: Int?
print(type(of:abc)) // Int
print(type(of:abcd)) // Optional<Int>
abc와 abcd의 타입이 저렇게 출력되는데,
다음 두개의 type형태는 같은 Int형이 아닌 다른 type형태이다.
abc는 Int Type형태인것이고, abcd는 Optional<Int> Type이 되는것이다.
다음 사진과 같이 Optional<Int>형은 Int형이 Optional로 포장되어있는 형태이다.
이러한 옵셔널로 감싸진 타입을 사용하기 위해서는 포장지를 벋겨주어야하는데,
그 과정을 Optional Unwrapping이라고 부른다.
Optional Unwrapping
옵셔널화된 변수를 다시 일반적으로 사용하기 위하여 필수인 과정이다.
다음과 Optional이된 변수가 있다.
var age: Int?
age = 25
print("제 나이는 \(age)입니다.")
이렇게 되면 제 나이는 25입니다. 라고 찍힐줄 알았다면 착각이다.
놀랍게도 제 나이는 Optional(25)입니다. 라고 찍히게된다.
그럼 이제 이 Optional타입을 Non-Optional 타입으로 바꿔줘야 하는데, 이 과정을 Optional Unwrapping이라고 한다.
Optional Unwrapping에는 한가지 주의점이 있는데,
Unwrapping을 하고자하는 변수나 상수의 값이 nil이면 절대 안된다.
Optional Unwrapping에는 몇가지 방법이 있는데, 그 중 첫번째는
강제 추출이다.
강제 추출
옵셔널 선언된 변수, 상수 뒤에 ! 를 붙이면된다.
이 방법은 변수, 상수의 값이 무엇이던지 강제로 Optional Unwrapping을 하는것 이다.
var age: Int?
age = 25
print("제 나이는 \(age!)입니다.")
위에 옵셔널 됐던 코드와는 age뒤에 ! 하나 차이뿐이지만 다음 코드는 제 나이는 25입니다. 의 값을 나타낸다.
하지만 강제로 언래핑을 하기 때문에 컴파일 에러가 되게 자주나서 잘 쓰지 않는다.
또 다른 방법은 Optional Binding이다.
옵셔널 바인딩 (Optional Binding)
옵셔널 바인딩은 옵셔널의 값의 존재 유무를 검사한 뒤,
존재한다면 그 값을 다른 변수에 대입시킨다.
따라서 강제 추출과는 다르게 안전하게 Optional Unwrapping을 하는 방법이된다.
옵셔널 바인딩의 예제로는
if let name: 타입 = OptionalExpresiion{
}
guard let name: 타입 = OptionalExpresiion else{
}
등이 있는데 위 표현식들의 공통점은
1. 옵셔널 표현식을 먼저 평가한다.
2. 값이 있는 경우 ( nil이 아닐 경우 ) 정의된 변수에 옵셔널 해제된 값을 저장하고 true를 반환한다.
3. nil인 경우 false를 반환한다.
4. 타입추론을 한다.
라는 공통점이 있다.
1. if let
첫번째로 if let을 활용한 방법이다.
우선 예제부터 살펴보겠다.
let optionalNumber: Int? = 1
if let optionalBindingNumber = optionalNumber{ // optionalNumber가 nil이 아닐 경우
print(optionalBindingNumber)
}else { // optionalNumber가 nil일 경우
print(optionalNumber)
}
다음과 같은 예제에서는 Optional(1)이라는 값이 아니라 Int형인 1 이 나온다.
만약 optionalNumber가 nil이었다면, nil이 출력된다.
이 식은 다음과 같은 과정을 걸쳐서 optional unwrapping을 하는데,
먼저 값이 nil인지 아닌지 nil check를 우선한다.
다음과 같이 if let문에 상수, 변수를 넣어 nil check를 진행한 후, 값이 nil이 아니라면
if문의 실행문을, 만약 값이 nil이라면 else문 실행문을 실행한다.
다음과 같은 if let문은 다음과 같은 속성이 있는데
let optionalNumber: Int? = 1
if let optionalBindingNumber = optionalNumber{ // optionalNumber가 nil이 아닐 경우
print(optionalBindingNumber)
}else { // optionalNumber가 nil일 경우
print(optionalNumber)
}
print(optionalBindingNumber) // compile error
다음과 같이 if let으로 선언된 상수의 범위는 if문안에서만 국한되므로
if문 밖에서는 if let으로 선언된 상수를 사용할 수 없다.
또한 if let으로 optional binding을 한다고 해도 optionalBindingNumber와 optionalNumber의 타입은 다르다.
여전히 optionalNumber의 값은 Optional(1)이고, optionalBindingNumber의 값만 1이다.
+++
let number1: Int? = 1
let number2: Int? = nil
if let number1 = number1, let number2 = number2 , number1 > 0 {
// ....
}else {
// ....
}
다음과 같이 두 상수, 변수의 이름을 같은 이름으로 설정하여도 되고,
한번에 여러개를 optionalBinding하거나, 조건을 달수도 있다.
위와 같은 경우는 위에 모든 식이 true를 충족해야만 if문을 실행하고, 아닐경우 else문을 출력한다.
다음식은 number2의 값이 nil값이므로 하나가 false가 되어 else문을 출력한다.
2. guard let
guard문은 swift에 있는 특이한 문법으로 메소드안에서만 사용되며,
조건을 만족하지 못하면 else문으로 빠져 return값을 받는다.
마찬가지로 예시부터 본다면,
let optionalNumber: Int? = 1
guard let optionalBindingNumber = optionalNumber else {
return
}
//...
다음과 같이 nil check를 실행한 뒤 값이 nil이라면 else문안에 실행코드를
값이 nil이 아니라면 guard문 밖으로 빠져나간다.
guard문은 if let과 다른점으로 guard문에서 선언된 변수, 상수를 guard문 밖에서 활용 가능하다.
let optionalNumber: Int? = 1
guard let optionalBindingNumber = optionalNumber else {
return
}
print(optionalBindingNumber)
다만, guard let으로 선언된 변수, 상수의 범위는 guard문 밖에서만! 가능하므로
else문안에서는 사용할 수 없다.
let optionalNumber: Int? = 1
guard let optionalBindingNumber = optionalNumber else {
print(optionalBindingNumber) // compile error
return
}
//...
또 다른 차이점은 if let은 옵셔널타입의 값과 옵셔널 언래핑된타입의 변수, 상수명을 동일하게 해도 됐지만,
guard let문은 메소드의 매개변수로 들어온 표현식에 한하여만 가능하다.
// 같은 이름으로 선언 불가능
func cantSameName() {
let number: Int? = 4
guard let number = number else{
return
}
}
// 같은 이름으로 선언 가능
func canSameName(_ number: Int?) {
guard let number = number else {
return
}
}
그리고 guard let문은 if let문과 같이 한번의 여러개를 unwrapping하거나 조건을 달 수 있다.
func manyCondition(_ number1: Int?, _ number2: Int?){
guard let number1 = number1, let number2 = number2 , number1 > 0 else {
return
}
}
'iOS > Swift 정리' 카테고리의 다른 글
Swift 클로저( closure ) (0) | 2021.09.30 |
---|---|
Swift 1급 객체 / 시민 (0) | 2021.09.29 |
Swift 조건문 (0) | 2021.09.09 |
Swift 튜플 (TUPLE) (0) | 2021.09.06 |
Swift 변수, 상수 (0) | 2021.09.06 |