개발 환경 : Xcode 12.1

사용언어 : swift

애플은 데이터의 json으로의 encode / decode를 지원하기 위해서 codable이란 프로토콜을 지원하고 있다 (Xcode 9.0+)

developer.apple.com/documentation/swift/codable

 

Apple Developer Documentation

 

developer.apple.com

해당 프로토콜을 이용해서 쉽게 json 데이터를 다룰 수 있다. 특히 파일 저장이나 rest api 응답을 받아서 처리할 때 유용하다.

임의의 구조체를 선언하고 codable을 상속 받기만 하면 일단 사용할 준비가 완료 된다.

다음과 같은 임의의 구조체가 있다고 가정해보자.

import Foundation
struct bigSur : Codable {
let message: String
let req_id:String
let result:String
let data : bslistOut
}
struct bslistOut : Codable {
let bsList: [bsListInner]
}
struct bsListInner : Codable {
let bs_addr1 :String
let bs_addr2 :String
let bs_id :Int
let bs_key :String
let bs_nm : String
let dist : Double
}
view raw BigSur.swift hosted with ❤ by GitHub

1. 구조체를 json string으로 

해당 구조체를 이용해서 생성한 데이터를 json string으로 바꾸어서 파일까지 저장한다면 다음과 같이 구현할 수 있다.

func saveJsonData(data:bigSur) {
let jsonEncoder = JSONEncoder()
do {
let encodedData = try jsonEncoder.encode(data)
print(String(data: encodedData, encoding: .utf8)!)
guard let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileURL = documentDirectoryUrl.appendingPathComponent("sampleData.json")
do {
try encodedData.write(to: fileURL)
}
catch let error as NSError {
print(error)
}
} catch {
print(error)
}
}

 

json string으로 변환했을 때까지를 출력하면 다음과 같이 나온다.

{
"result": "success",
"message": "sentMsg",
"data": {
"bsList": [
{
"bs_id": 1,
"bs_addr2": "222",
"bs_key": "333",
"bs_addr1": "111",
"bs_nm": "444",
"dist": 0.5
},
{
"bs_id": 2,
"bs_addr2": "555",
"bs_key": "666",
"bs_addr1": "444",
"bs_nm": "777",
"dist": 0.69999999999999996
},
{
"bs_id": 3,
"bs_addr2": "888",
"bs_key": "999",
"bs_addr1": "777",
"bs_nm": "000",
"dist": 0.80000000000000004
}
]
},
"req_id": "a011999"
}
view raw jsonString.txt hosted with ❤ by GitHub

 

2. json string을 구조체로

json 으로 저장된 파일에서 원하는 구조체로 읽어 내는 것은 다음과 같이 사용할 수 있다.

func loadJsonFile() -> bigSur?{
let jsongDecoder = JSONDecoder()
do {
guard let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil}
let fileURL = documentDirectoryUrl.appendingPathComponent("sampleData.json")
let jsonData = try Data(contentsOf: fileURL, options: .mappedIfSafe)
let decodedBigSur = try jsongDecoder.decode(bigSur.self, from: jsonData)
return decodedBigSur
}
catch {
print(error)
return nil
}
}

 

3. Date 형식의 경우

codable 프토로콜을 상속 받더라도 json 문법에 맞지 않는 Date 같은 데이터는 처리할수가 없는데

명시적으로 처리하는 방법을 알려준다면 encode/decode가 가능해진다.

encoding 할 경우 다음과 같이 추가해준다면, Date 형식을 읽고 쓰는데 문제가 없다.

jsonEncoder.dateEncodingStrategy = .formatted(DateFormatter.iso8601Full)
extension DateFormatter {
static let iso8601Full: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}

 

*처음으로 코드를 캡쳐 대신에 gist를 써보니 깔끔하네요

by 무위자연 2020. 11. 19. 11:57