일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 100 days of SwiftUI
- UserDefaults
- 상호배제
- 알고리즘
- Apple Developer Academy
- IOS
- Swift
- COLOR
- deadlock
- 운영체제
- 가상 메모리
- forEach
- scrollview
- Linked List
- 앨런
- Algorithm
- @state
- core data
- 인프런
- async
- decode
- 동기화
- 프로세스 스케줄링
- SwiftUI
- 데드락
- 오브젝트
- 비동기
- struct
- 동시성
- Codable
Archives
- Today
- Total
기어가더라도 제대로
[SwiftUI-기초] @Published 프로퍼티를 지닌 Codable 타입 저장 본문
2022.11.23 - [SwiftUI - 기초] - [SwiftUI-기초] UserDefaults 와 SwiftUI
이 글은 위의 포스팅의 후속편입니다.
위의 글은 User 타입이 구조체였지만 이번 포스팅에서 다룰 내용은 User가 클래스고
@Published 속성의 프로퍼티를 가지고 있을 때 대처하는 방법입니다.
Struct + Codable
struct User: Codable { }
- 구조체의 타입을 Encodig, Decoding하는 방법은 별다를게 없고, Codable만 설정해주면 됩니다.
- 자동적으로 Encoding, Decoding 로직이 돈다는 것이죠.
- 요약하자면 Struct 타입을 디스크에 저장하는 방법은 Codable 을 이용한다는 것입니다.
Class + Codable + @Published ...?
class User: ObservableObject, Codable {
@Published var name = "Damagucci_Juice"
}
- 위의 타입을 구조체에서 클래스로 변경하라하면 이렇게 할 거 같습니다.
- 그렇지만 이 코드는 빌드가 안되는 단점이 있는데요.
- 왜 그럴까요?
@Published
- 이 속성은 오는 타입을 발행해주는 마법같은 존재라기보단 내부적으로 어떤 타입으로 변환시켜주는 것입니다.
- 위의 name 프로퍼티는 원래 String 타입이지만, @Published가 붙으면 Published<String> 타입이 되는 것이지요.
- 마치 Set, Array, Dictionary 와 역할이 비슷하네요.
- Set<Int> 는 Int가 아니죠. Int의 Set이죠.
- @Published 된 프로퍼티는 Published<Value> 가 되는 것입니다.
Array, Set, Dictionary <-> @Published
- 공통점: 위 제목에 나온 타입들은 그들 내부에 특정한 타입을 가져야한다는 것입니다.
- 예) Set<Int>, Array<String>, Published<Int>
- 차이점:
- 왼쪽들은 오는 Value가 Codable 을 채택할 수 있다면 합쳐진 타입도 Codable합니다.
- 예) Int + Array = [Int], Int 타입이 Codable 하면 [Int] 도 Codable합니다.
- @Published 는 그렇지 않죠.
- 예) Int + Published = Published<Int>, Int 타입이 Codable 하지만 Published<Int> 는 Codable 하지 않습니다.
- 우리의 목표는 Published<Value> 타입을 Codable 하게 만들면 되겠네요!
@Published 를 Codable 채택하게 만들기
User 클래스가 Codable 하게 되려면 Published<Value> 타입의 Codable이 가능해져야합니다.
그런데 말입니다. Codable이 무어란 말입니까? 어떤 타입이 Encoding 되고 Decoding 될 수 있음을 보장하는 프로토콜입니다.
그러면 클래스의 모든 프로퍼티에 대해서 Encoding, Decoding 하는 방법을 마련해준다면 Codable을 채택할 수 있겠죠?
CodingKeys
- CodingKey 라는 프로토콜을 채택한 열거형을 만들면 되는데 보통 이런식으로 많이 합니다.
- User 클래스 내부의 중첩 타입으로 선언합니다.
enum CodingKeys: CodingKey {
case name
}
- Archive 와 Unarchive 하려는 모든 프로퍼티를 나열해줍니다.
- 우리의 경우엔 name 프로퍼티 하나 있으므로 name 케이스 하나만 적습니다.
Decoding(Unarchiving) - Custom Initializer
- User 클래스가 생성될 때 디스크에 저장되어 있는 값이 있다면 Decoding(Unarchiving)을 해줘야합니다.
- 커스텀 이니셜라이저를 사용해서 해보겠습니다. 다음의 4단계를 거칩니다.
- 1. Decoder 타입의 인스턴스를 매개변수로 받습니다.
- 2. User 의 하위 클래스들도 이 과정을 거칠 수 있도록 커스텀 이니셜라이저를 required 로 선언해줍니다.
- User가 상속하지 않는다면 final 키워드를 붙여줌으로써 required 넣기를 생략합니다.
- 3. Decoder 인스턴스로 Container 를 불러옵니다. 컨테이너는 CodingKeys 에서 정의한 코딩키들에 매칭됩니다.
- 이 과정에서 Key 가 존재하지 않을 수 있어서 오류의 가능성이 있어 throws 으로 에러 가능성을 내포합니다.
- 4. 코딩키에 있는 케이스를 참조해 컨테이너로부터 값을 직접 읽을 수 있습니다.
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
}
Encoding(Archiving) - func encode(to: )
- 위의 Decoding 과정과 반대되는 경우입니다.
- Decoding + Encoding = Codable 이니까 필요합니다.
- 과정은 Decoding 과 비슷합니다.
- 1. Encoder 타입의 인스턴스를 파라미터로 받습니다.
- 2. encoder 로 CodingKeys 의 케이스에 맞게 container를 불러옵니다.
- 3. 각각의 key 에 해당하는 value 를 저장합니다.
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CondingKeys.self)
try container.encode(name, forKey: .name)
}
결론
- struct 는 Codable 하려면 Codable 프로토콜만 채택하면 그만이였지만 class 는 디테일하게 encoding, decoding 하는 법을 정의해야합니다.
- CodingKeys 는 프로퍼티의 오탈자 가능성을 없애줍니다.(비교: 2022.11.23 - [SwiftUI - 기초] - [SwiftUI-기초] UserDefaults 와 SwiftUI)
'SwiftUI - 기초' 카테고리의 다른 글
[SwiftUI-기초] 비동기적 이미지 뷰 - AsyncImage() (0) | 2022.11.26 |
---|---|
[SwiftUI-기초] URLSession 으로 Codable Data 받아오기 (0) | 2022.11.25 |
[SwiftUI-기초] UserDefaults 와 SwiftUI (0) | 2022.11.23 |
[SwiftUI-기초] Shape 를 복잡한 애니메이션 주기 (0) | 2022.11.22 |
[SwiftUI-기초] Shape 를 애니메이션 주기 - animatableData (0) | 2022.11.21 |
Comments