iOS에서 JSON형태로 로컬파일 저장하기(JSON using coable)
- Develop/Swift
- 2020. 10. 31.
반응형
728x90
반응형
Introduction
이번 포스팅은 SwiftUI를 이용하여 iOS App을 개발하는데 있어 필요한 모듈입니다. 이 모듈은 iOS기기 내부 로컬에 파일에 JSON형태로 저장을 하는 모듈입니다. 하지만, 이 모듈을 이용해서 쉽게 저장/로드 할 수 있지만, 몇몇 특이한 형태의 구조를 가지는 클래스/구조체/열거체의 경우 저장하는 모듈이 제대로 수행되지 않습니다. 조금의 삽질 끝으로 문제점과 해결방법을 알아보도록 하겠습니다.
JSON 모듈을 save/load 하기위해서 github 혹은 cocoapods 에서 아래의 Library를 검색 가능합니다.
문제점(Problem)
먼저 문제점을 확인해보도록 하겠습니다. 상위 라이브러리를 이용하여 쉽게 저장/로드를 쉽게 수행할 수 있습니다. 하지만 아래의 열거체를 그대로 JSON형태로 저장할 때 오류가 발생하게 됩니다.
enum TalkDirection: Int, Codable {
case left
case right
}
TalkDirection 열거체에는 Codable이 있지만 Decodable이 없습니다.
enum TalkMsgType: Int, Codable {
case message
case image
case webLink
case emotion
}
TalkMsgType 열거체 또한 Codable이 있지만 Decodable이 없습니다.
struct Talk: Codable, Identifiable {
let id:UUID = UUID()
var Name:String
var Message:String
var Direction:TalkDirection
var type:TalkMsgType
init(_ name:String, _ message:String, _ direction:TalkDirection, _ type:TalkMsgType){
self.Name = name
self.Message = message
self.Direction = direction
self.type = type
}
}
그리고 Talk 구조체에서는 상위 TalkDirection 및 TalkMsgType 열거체를 가지고 있습니다. 이러한 구조체를 JSON형태로 저장을 해야합니다. 하지만, 열거체의 경우, 어떤 Type의 값을 가지는지 알수 없어 JSON형태로 변환 할 수 없습니다.
해결방법(Solve)
해결방법은 생성자(init)를 이용하여 Decoder를 구현하는 것입니다. 그리고 반대로 encode를 할 경우 따로 함수를 만들어서 사용하면 됩니다. 문제를 해결하기위해 열거체에서 extension을 이용하여 아래와 같이 코드를 추가합니다.
extension TalkDirection {
private enum CodingKeys: String, CodingKey {
case left
case right
}
enum CodingError: Error {
case decoding(String)
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
if let value = try? values.superDecoder(forKey: .left){
self = .left
return
}
if let value = try? values.superDecoder(forKey: .right){
self = .right
return
}
throw CodingError.decoding("Error: TalkDirection-init()")
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .left:
try container.encode("left", forKey: .left)
case .right:
try container.encode("right", forKey: .right)
}
}
}
상위 코드와 같이 CodingKeys 부터 CodingError를 같이 구현해 주도록 합니다. 그리고 TalkMsgType 열거체도 동일하게 구현을 합니다.
extension TalkMsgType {
private enum CodingKeys: String, CodingKey {
case message
case image
case webLink
case emotion
}
enum CodingError: Error {
case decoding(String)
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
if let value = try? values.superDecoder(forKey: .message){
self = .message
return
}
if let value = try? values.superDecoder(forKey: .image){
self = .image
return
}
if let value = try? values.superDecoder(forKey: .webLink){
self = .webLink
return
}
if let value = try? values.superDecoder(forKey: .emotion){
self = .emotion
return
}
throw CodingError.decoding("Error: TalkDirection-init()")
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .message:
try container.encode("message", forKey: .message)
case .image:
try container.encode("image", forKey: .image)
case .webLink:
try container.encode("webLink", forKey: .webLink)
case .emotion:
try container.encode("emotion", forKey: .emotion)
}
}
}
열거체의 case에 따라 동일하게 구현하시면 됩니다. 그리고 열거체에 여러가지 타입들이 있지만, 이와 유사하게 구현하시면 됩니다.
이제 사용방법은 다음과 같이 코드를 작성하시면 됩니다.
func testTalkLog() {
var key:String = "TalkLog"
var TalkSamples = [
Talk("박민호", "안녕하세요",TalkDirection.left, TalkMsgType.message),
Talk("노은지", "안녕하세요",TalkDirection.right, TalkMsgType.message),
Talk("박민호", "SwiftUI 한잔 어때요?",TalkDirection.left, TalkMsgType.message),
Talk("노은지", "네, 좋아요 ",TalkDirection.right, TalkMsgType.message),
Talk("박민호", "어디서 볼까요?",TalkDirection.left, TalkMsgType.message),
Talk("노은지", "근처 카페에서 봐요",TalkDirection.right, TalkMsgType.message),
Talk("박민호", "네, 있다가 뵐께요",TalkDirection.left, TalkMsgType.message),
Talk("노은지", "네",TalkDirection.right, TalkMsgType.message),
]
do {
try storage.save(object: TalkSamples, forKey: key)
storage.cache.removeAllObjects()
let loadedUsers = try storage.load(forKey: key, as: [Talk].self)
print(loadedUsers)
try storage.remove(forKey: key)
}catch {
print("error: testUserInformation()")
}
}
상위 코드는 앞서 설명한 EasyStash Library를 이용하여 사용하시면 됩니다.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var myJSONTester:JSONTester = JSONTester()
myJSONTester.setUp()
myJSONTester.testTalkLog()
return true
}
그리고 Xcode에서 시뮬레이터를 이용하여 확인을 하기위해 application() 함수에 상위 코드와 같이 작성을 하시면 됩니다. 코드가 제대로 돌아가는지 확인을 하기위해서는 브레이크 포인트를 설정하고 디버깅 모드를 이용하여 출력되는 값 혹은 실행 중 값을 확인하시면 됩니다.
마무리
SwiftUI를 공부하면서 JSON형태로 iOS에 파일을 저장하는 부분을 찾아보았는데, 직접 구현하는 것을 시도해보는 것도 중요하지만, 기존에 만들어진 라이브러리를 어떻게 사용하고 활용하는지도 중요하다고 생각합니다.
728x90
반응형
'Develop > Swift' 카테고리의 다른 글
SwiftUI UserNotifications Library (0) | 2020.11.06 |
---|---|
SwiftUI UserNotifications 만들기 (0) | 2020.11.05 |
iOS App ICON 생성 및 추가방법 (0) | 2020.11.04 |
Xcode project .ignore file 추가하기 (0) | 2020.11.03 |
SwiftUI기반 iOS App 전체화면 색상변경 (0) | 2020.11.02 |
cocoapods 설치 및 사용방법 (0) | 2020.10.25 |
Xcode에서 SwiftUI 시작하기 (0) | 2020.09.02 |
Swift iOS파일 시스템 구조 (0) | 2020.08.31 |
Swift 아이콘(SF symbols app for MacOS) (0) | 2020.08.28 |
Xcode command line tools 추가 설치 (0) | 2020.08.21 |