옵셔널은 내가 선언한 변수/상수에 값이 존재하지 않을 수도 있을 때 선언해준다.
이 값이 존재하지 않는 것을 nil이라고 하는데, C에서의 null과 비슷하지만 쪼~~금 다르다.
수업 때는 교수님이 그냥 비슷한 거라고 하고 넘어가셨는데, 궁금해서 한번 알아보긴 했다.
null(c에서) : 가리키는 객체의 포인터가 아예 존재하지 않을 때.
nil : 클래스 객체(특정 타입)에 대한 값이 존재하지 않을 때.
swift가 옵젝씨에서 넘어온 거다 보니 옵젝씨의 잔재가 남아있는데,
옵젝씨에서는 nil과 null을 둘 다 썼다고 함.
근데 스위프트에는 포인터를 사용하지 않기 때문에 nil만 넘어왔다~는 것.
암튼 nil은 내가 만든 변수/상수에 값이 없다는 걸 의미한다.
만약 내가 선언한 var count에 값이 저장되지 않을 수도 있을 때는?
var count: Int?
로 선언해 주면 된다.
물음표가 옵셔널을 의미하는 거임!
만약에 문자열을 정수로 변환하는 동작을 할 때, 변환되지 않는 문자열이 있을 수도 있음.
var str1 = "123"
//str1 문자열은 정수로 변경 가능.
var str2 = "123a"
let convertedNumber1 = Int(str1)
let convertedNubmer2 = Int(str2)
//convertedNumber1 -> 123(변경됨)
//convertedNumber2 -> nil(변경안됨)
이런 식으로 문자열을 정수로 변경할 때, convertedNumber1, convertedNumber2는 이게 정수로 변경이 될수도 있고 안될수도 있기 때문에 정수형인 Int로 타입이 정해지는 게 아니고 Int? 인 optional Int로 타입이 정해지게 된다.
이렇게 만들어둔 옵셔널 변수/상수들의 값이 있는지 없는지 보고싶으면?? 요걸 언래핑이라고 한다. 여러가지 방법이 있음.
if를 사용해서 원하는 변수에 어떤 값이 있는지 확인할 수 있음.
if convertedNumber1 != nil{
//convertedNumber1에 값이 저장돼 있을 때 동작
}
else{
//convertedNumber1에 값이 없을 때 동작
}
이때 이 옵셔널 타입 값을 쓰고 싶다면?
if convertedNumber1 != nil{
print(convertedNumber1)
//Optional(123) 출력됨
print(convertedNumber1!)
//123 출력됨
}
else{
//convertedNumber1에 값이 없을 때 동작
}
이런 식으로 느낌표를 옵셔널 변수 뒤에다가 붙여주면 된다!
안 붙여주면 그대로 옵셔널 타입이 붙은 상태로 쓰여지기 때문에 오류가 날 수도 있다고 함.
요걸 강제 언래핑(forced unwrapping)이라고 한다.
만약 이 변수에 무조건 값이 있다고 확정됐다면 강제 언래핑을 통해서 사용하면 된다고 함.
상수에다가 옵셔널 값을 집어넣는 방법이다.
if let actualNumber = Int(str1) {
print("The string \"\(str1)\" has an integer value of \(actualNumber)")
}
else {
//str1을 정수형으로 변경 불가할 때 동작
}
이때 actualNumber에는 옵셔널 정수값이 저장되는 게 아닌 그냥 정수값이 저장되게 된다. 그냥 사용해도 되게 됨.
신기한 건 기존에 접근했던 옵셔널 변수를 더 이상 안 써도 될 때, if let 에다가 똑같은 이름의 상수를 선언해서 사용해도 된다.
그러면 기존의 옵셔널은 없어짐.
let num = Int(str1)
//num은 optional Int
if let num = num {
//num은 Int로 변경됨
print("My number is \(num)")
}
이거마저도 줄여버리고 싶다면?
let num = Int(str1)
if let num {
print("My number is \(num)")
}
이런 식으로 써도 됨!(근데 공식문서에는 이렇게 써도 된다고 하는데 왜 내 플레이그라운드에서는 안되지...?)
클로저 때도 느꼈지만 스위프트는 참 줄이는 걸 좋아하는 것 같다.별다줄
근데 if let은 어마어마한 단점이 있다. 바로 요 if let으로 만든 상수는 if문 밖에서 쓸 수가 없다는 것..
만약에
if let num = Int(str1){
print("My number is \(num)")
}
print("My number is \(num)")
이런 식으로 써두면 if구문 밖에서 num을 참조할 수 없다는 오류가 뜬다.
이걸 해결할 수 있는 방법은 바로바로!
guard let을 사용하는 것이다. guard라니.. 이름부터 든든해보임.
가드문을 사용하면 다른 곳에서도 똑같은 이름으로 사용이 가능하다.
guard let num = Int(str1) else{
//nil일때 동작
}
print(num)
//123
이런 식으로 guard let으로 언래핑이 가능한데, if let은 else문이 없어도 괜찮았지만 guard let은 무조건 else가 있어야 한다.
보통 함수 안에서 이걸 사용하면 else에다 return을 넣어서 함수블록을 종료시킴.
guard let의 블록보다 상위 블록을 종료하는 코드가 반드시 else에 들어가야 한다.
return, continue, break, throw 등을 넣음.
그래서 함수나 반복문 등 특정 블록 안에 들어가있지 않으면 guard let을 사용할 수가 없다.
가끔 옵셔널 변수가 항상 값이 존재할 것이 보장되는 때가 있다.
옵셔널이 지정된후, 거의 바로 해당 변수의 값이 존재할 때, 느낌표(!)를 자료형에다 달아준다.
let possibleString: String? = "An optional string."
let forcedString: String = possibleString!
// requires an exclamation point
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString
// no need for an exclamation point
이렇게 그냥 옵셔널은 느낌표(!)로 옵셔널을 언래핑해주는 과정이 필요하지만, 암시적 언래핑(Implicitly unwrapped)된 건 딱히 언래핑해줄 필요 없이 바로 사용이 가능하다.
다른 연산은 모~~두 ?를 사용하는 옵셔널과 같지만 사용하는 부분에서 !를 달아주지 않아도 된다는 장점이 있음!!