스위프트를 공부하면
?
!
같은 기호들을 보게되죠
이게 뭐냐면
옵셔널이라는 개념인데요
개념을 공부해보고 한번 비슷하게(?) 구현해보려구요
Enum타입이고
값 또는 nil을 wrap한 표현이레요
옵셔널이란
값이 있거나 없을 수도 있는 Enum형(열거형)타입이에요
let shortForm: Int? = Int("42")
let longForm: Optional<Int> = Int("42")
let number: Int? = Optional.some(42)
let noNumber: Int? = Optional.none
print(noNumber == nil)
// Prints "true"
Optional<T> 타입을
짧게 T? 로 줄여서 사용할 수 있어요
또한 옵셔널은 Enum타입에
case로 some, none
이 존재해요
Optional.some(T)를 값으로 넣어 줄 수 있고 some은 제네릭타입으로 구현되어있어요
Optional값을 사용할 땐
Optional로 쌓여있기 떄문에 벗겨내고 사용해야 그 값을 잘 사용할 수 있겠죠?
let a: Int? = 3
let b: Int = 3
print(a) // Optional(3)
print(b) // 3
이렇게 옵셔널을 이용한 값에서 Optional이 거슬리잖아요? ㅎㅎ
옵셔널 값 가져오기
값을 가져오는 방법에는
1. 강제언래핑(!)
2. 옵셔널바인딩(Optional Binding)
3. Nil병합 연산자(Nil-Coalescing Operator)
4. 옵셔널체이닝(Optional Chaining)
강제언래핑(!)
위에서 언급했던 ! 이에요
!는 강제로 옵셔널을 해제시키는거에요
헷갈리는 경우가 있죠
타입으로 사용하는 !과
강제언래핑으로 사용하는 !
먼저 타입으로사용하는 !는
let a: Int! = 3
Int!타입으로 타입명시를 해도
Optional타입이에요 하지만
없을수도 있다를 나타내지않아요
무슨 말이냐면
이 값은 존재한다를 명시해주는거에요
그래서 구조체나 클래스를 정의할때 멤버변수를 모두 생성자에서 초기화 해줘야하지만
?나 !를 이용하면 생성하지 않아도돼요
이런경우 ?는 값이 없어도 문제가 되지않지만
!는 문제가되요 nil에 접근을 하면 에러가나요
!는 값을 읽을때 옵셔널을 벗겨서 가져오기때문에 nil이라면 앱이 죽겟죠?
옵셔널타입에 !를 사용하는 강제언래핑인경우
옵셔널안에 값이 있다고 생각하고 무조건 꺼내오는거에요
뭐가 들었는지 모르는 상자를 뜯어 보는거죠
하지만 꺼냈더니 폭탄(nil)이라면 죽겠죠?? ㅎㅎ
값이 존재하는 확실한 경우에만 강제언래핑을 통해 꺼내오는거에요
귀찮거나.. 로직이 복잡해질거같을때 말이죠
강제언래핑은 위험한 방법이지만
아래부터는 안전한 방법이에요
옵셔널바인딩(Optional Binding)
if let starPath = imagePaths["star"] {
print("The star image is at '\(starPath)'")
} else {
print("Couldn't find the star image")
}
imagePaths는 옵셔널타입이죠 Dictionary의 value는 항상 옵셔널이에요(키에 따른 값이 있을지 없을지 모르기때문에)
그 옵셔널을 startPath 변수로 넣어주면서 앞에 if가 붙었죠
if let 과
guard let
이 옵셔널 바인딩 방법이에요
if let은 해당 스코프 안에서만 변수를 사용할 수 있고
guard let은 변수가 선언된 스코프안에서 변수를 사용할 수 있어요
무슨말이냐면
let opt: Int? = 3
if let a = opt {
print(a) // 사용가능
}
print(a) // 사용불가
guard let b = opt else {
print(b) // 사용불가
return
}
print(b) // 사용가능
그리고 guard let에서 조건에 안맞는다면 그위치에서 코드가 무조건 끝나기 때문에
if let과 차이가 있죠
저 같은경우
if let은 그 코드와 상관없이 아래에 코드가 실행되어야 하는경우에 사용하고있고
guard let은 그 코드에서 막힌다면 아래를 볼 필요가 없을 때 사용하고 있어요
Nil병합 연산자(Nil-Coalescing Operator)
let opt: Int? = 3
print(opt ?? 100) // 3
??를 사용하는 방법이에요
?? 뒤에 nil인경우 기본값을 설정해줘서 무조건 값이 생기기때문에 옵셔널을 까고 값이 나오게돼요
옵셔널체이닝(Optional Chaining)
let a: String? = "1234"
print(a?.count) // Optional(4)
해당 변수가 옵셔널타입인경우 뒤에 ?를 붙여서 속성 및 메서드에 안전하게 접근할 수 있는 방법이에요
만약 a가 nil이면
a.count는 에러가 나겠죠??
하지만
옵셔널 체이닝을 통해서
a?.count를 사용해서 a가 nil이라면
옵셔널 형태로 사용할 수 있어요
옵셔널 구현(?)
이 구현이 맞는지 모르겠지만 비슷하게 따라해봤어요
내부 코드를 알 수 없기에...
코드부터 보면..
enum TestOptional<Wrap>: ExpressibleByNilLiteral, CustomDebugStringConvertible {
var debugDescription: String {
switch self {
case .some(let value):
return "Optional(\(value))"
case .none:
return "nil"
}
}
case none
case some(Wrap)
init(_ some: Wrap) {
self = .some(some)
}
init(nilLiteral: ()) {
self = .none
}
}
// 테스트실행 코드
let test: Int? = 1
let test1 = Optional.some(1)
let a = TestOptional(11)
let b = TestOptional<Int>.some(11)
let c = TestOptional<Int>.none
let d = TestOptional<Int>(nilLiteral: ())
print(test) // Optional(1)
print(test1) // Optional(1)
print(a) // Optional(11)
print(b) // Optional(11)
print(c) // nil
print(d) // nil
some, none 케이스가 존재하고
some은 제네릭타입으로 값을 받죠
Optional.some() <=> TestOptional.some() 처럼 사용 가능하구요
값을 넣어주고 출력하면
TestOptional.some이 뜰텐데
이를
디버그창에 다르게 뜨도록 커스텀해봤어요
CustomDebugStringConvertible프로토콜을 채택하고
디버그될때 보여질 출력문을 변경 할 수 있어요
ExpressibleByNilLiteral를 사용해서 nil 인스턴스를 만들 수 있게했구요
옵셔널타입보니 채택하고 있어서 따라해봤어요 ㅎㅎ
'iyOmSd > Title: Swift' 카테고리의 다른 글
[Swift] AutoLayout 코드작성방법 (Visual Format Language, NSLayoutAnchor, NSLayoutConstraint) (0) | 2020.11.27 |
---|---|
[Swift] Hugging, Resistance (0) | 2020.11.25 |
[Swift] Notification Center, Notification Queue (0) | 2020.11.20 |
[Swift] Fastlane 자동화빌드 배포 CI/CD (2/2) (0) | 2020.11.19 |
[Swift] Fastlane 자동화빌드 배포 CI/CD (1/2) (0) | 2020.11.19 |