위키백과에 나온 JSON의 정의는 다음과 같다.
JSON(JavaScript Object Notation)은 "키-값 쌍"으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준 포맷이다.
어플리케이션을 만들면서 거의 필수적으로 해야 하는것.. 바로 API 호출인데, 요즘은 거의 대부분 API 호출로 JSON
형식의 데이터를 받기 때문에 JSON
데이터를 다루는 것은 필수라고 생각된다.
추가적으로 어플리케이션의 데이터를 추가할 때도 JSON 형태로 사용할 수 있고..아무튼 많은 곳에서 사용이 된다.
Swift에서 JSON 데이터를 Encoding하고 Decoding하는 방법에 대해 알아보자!
JSON encoding과 decoding에 앞서 알아야 할 것이 바로 Codable
protocol이다.
Apple document에는 다음과 같이 정의 되어 있다.
typealias Codable = Decodable & Encodable
정의 자체도 Decodable
protocol과 Encodable
protocol을 조합한 사용자 정의 타입인 것을 알 수 있다.
Decodable
protocol과 Encodable
protocol은 각각 디코딩과 인코딩을 가능하게 하는 protocol이며
Codable 타입을 준수하는 데이터는 Foundation
framework에 정의 되어 있는 JSONDecoder
, JSONEncoder
를 통해 데이터를 디코딩, 인코딩 할 수 있다.
이제 실제로 데이터를 디코딩과 인코딩을 하는 법을 알아보자
먼저 JSON 데이터를 인코딩 하기 전에 파싱(parsing)
을 위한 구조체를 먼저 정의한다.
예시로 유저 정보를 담기위한 구조체로 유저의 이름과 나이, e-mail, 자택 주소를 데이터로 가지는 구조체를 정의 했다.
import Foundation
struct Person: Codable {
var name: String
var age: Int
var mail: String
var address: String
}
인코딩과 디코딩에 사용될 타입은 반드시 Codable
protocol을 채택할 것을 잊지 말자!
그리고 인코딩에 사용될 샘플 데이터를 아래와 같이 생성하였다.
let personKim: Person = Person(name: "김철수", age: 99, mail: "kim@mail.com", address: "서울특별시 종로구")
let personLee: Person = Person(name: "이영희", age: 20, mail: "lee@mail.com", address: "부산광역시 연제구")
이제 샘플 데이터를 JSON 데이터로 인코딩해 줄 차례이다.
func jsonEncoder(_ data: Codable) -> String? {
var encoder = JSONEncoder()
do {
let jsonData = try encoder.encode(data)
return String(data: jsonData, encoding: .utf8)
} catch {
print("encoding error")
}
return nil
}
먼저 JSONEncoder
인스턴스를 생성하기 위해서는 Foundation
framework를 반드시 import 해야한다.
만약 잘못된 데이터를 받아 올 경우 오류를 피하기 위해 do-catch
문으로 오류를 처리해 주었고 인코딩 실패에 대비하여 반환 타입 또한 optional 타입으로 정의 하였다.
그리고 콘솔 창에 JSON 데이터의 내용은 바로 출력이 되지 않기 때문에 JSON 데이터를 인코딩 후 String
타입으로 한번 더 인코딩 해 주었다.
여기서 String 타입 initializer의 parameter 내용은 다음과 같다.
init(data:encoding:)
Data
타입의 전달인자를 받는다.utf8
방식으로 인코딩 하였다.JSON 인코딩으로 나온 결과 값은 다음과 같다.
print(jsonEncoder(personKim)!)
//{"age":99,"mail":"kim@mail.com","name":"김철수","address":"서울특별시 종로구"}
조립은 분해의 역순이라는 말이 있다.
JSON 형식으로 인코딩된 데이터를 다시 디코딩 하는 방식은 인코딩의 역순으로 돌아가면 된다.
마찬가지로 JSON 데이터를 디코딩할 함수를 만들어 준다.
func jsonDecoder(_ data: String) -> Person? {
var decoder = JSONDecoder()
guard let jsonData = data.data(using: .utf8) else { return nil } //Data type으로 디코딩
do {
let decoded: Person = try decoder.decode(Person.self, from: jsonData)
return decoded
} catch {
print("decoding error")
}
return nil
}
아까 인코딩에서 반환한 String 타입의 데이터를 String 타입의 data
method를 이용하여 다시 Data
타입으로 디코딩한다.
디코딩된 데이터를 JSONDecoder
인스턴스의 decode
method를 이용하여 다시 Person 타입으로 디코딩한다.
decode
method의 parameter 내용은 다음과 같다.
decode(_:from:)
from
매개변수로는 디코딩할 데이터가 전달된다.이렇게 디코딩된 결과 값은 다음과 같다.
let JSONData = jsonEncoder(personLee)!
let decoded = jsonDecoder(JSONData)
print(decoded!.name) //이영희