Codable을 사용하면 decodable과 encodable 프로토콜을 둘다 적용할 수 있다.
만약 decodable만 쓸거라면 반드시 Codable을 써야 할 필요는 없다.
(decodable만 써도 되니까)
typealias Codable = Decodable & Encodable
Codable is a type alias for the Encodable and Decodable protocols.
When you use Codable as a type or a generic constraint, it matches any type that conforms to both protocols.
protocol Decodable
// A type that can decode itself from an external representation.
protocol Encodable
A type that can encode itself to an external representation.
Encodable -> data를 Encoder에서 변환해주려는 프로토콜로 바꿔주는 것
Decodable -> data를 원하는 모델로 Decode 해주는 것
위의 정의에서 external representation을 json이라고 예로 들자면,
Encodable -> 모델을 json으로 인코드
Decodable -> json을 내가 원하는 모델로 디코드
만국박람회 프로젝트의 경우 json 파일에 있는 내용을 모델 객체에 decode 해주는 것.
출처: Swift :: Codable 알아보기 by 상어
import Foundation
struct Coffee : Codable {
var coffeeName : String
var coffeeprice : Int
}
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys, .prettyPrinted]
let caffeLatte = Coffee(coffeeName: "카페 라떼", coffeeprice: 4000)
let jsonData = try? encoder.encode(caffeLatte)
if let jsonData = jsonData, let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}
encoder.outputFormatting = [.sortedKeys, .prettyPrinted] 해주기 전 출력 모습
{"coffeeprice":4000,"coffeeName":"카페 라떼"}
encoder.outputFormatting = [.sortedKeys, .prettyPrinted] 해준 후의 출력 모습
→ sortedKeys는 알파벳 순으로 정렬
→ prettyPrinted는 줄바꿈을 해줘서 이쁘장하게 출력해준다.
{
"coffeeName": "카페 라떼",
"coffeeprice": 4000
}
인코딩은 됐는데 디코딩이 안된다...
인코딩 값만 제대로 나오고 끝남 ㅠㅠ
예정에 없던 숨은 그림 찾기를 해보았다 ^.^
다음 중 잘못된 것은??
import Foundation
struct Coffee : Codable {
var coffeeName : String
var coffeeprice : Int
}
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys, .prettyPrinted]
let caffeLatte = Coffee(coffeeName: "카페 라떼" coffeeprice: 4000)
let jsonData = try? encoder.encode(caffeLatte)
if let jsonData = jsonData, let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
}
let jsonString = """
{
"coffeeName" : "카페 라떼"
"coffeeprice" : 4000
}
"""
let decoder = JSONDecoder()
var data = jsonString.data(using: .utf8)
if let data = data, let myCoffee = try? decoder.decode(Coffee.self, from: data) {
print(myCoffee.coffeeName)
print(myCoffee.coffeeprice)
}
정답
안되는 이유를 Kane이 찾아줬다...
jsonString 안에서 카페 라떼하고선 컴마를 빼먹었다 😅
휴먼 에러를 구현할 계획이 없었는데
몸소 보여줬다 ^.ㅠ
다른 개선점은 카멜케이스를 적용하지 않았던 coffeeprice를 coffeePrice로 고쳐줬다.
같이 고민해준 탁, 스티븐, 케인 고맙습니다 😉 👍
import Foundation
struct Coffee : Codable {
var coffeeName : String
var coffeePrice : Int
}
// string을 여러줄로 할때 """로 묶어줌
let jsonString = """
{
"coffeeName" : "카페 라떼",
"coffeePrice" : 4000
}
"""
let decoder = JSONDecoder()
var data = jsonString.data(using: .utf8)
if let data = data {
if let myCoffee = try? decoder.decode(Coffee.self, from: data) {
print(myCoffee.coffeeName) // print 카페 라떼
print(myCoffee.coffeePrice) // print 4000
}
}
출처
Swift ) 왕초보를 위한 Codable / JSON Encoding and Decoding [ZeddiOS]
Encode and Decode Automatically
Encode or Decode Exclusively
Encode나 Decode 둘 중 필요한 것만 아래처럼 골라써라.
struct Landmark: Encodable {
var name: String
var foundingYear: Int
}
struct Landmark: Decodable {
var name: String
var foundingYear: Int
}
Choose Properties to Encode and Decode Using Coding Keys
Codable 타입은 특별히 타입 내부에서 쓸 수 있는 CodingKeys라는 이름의 열거형을 쓸 수 있음
CodingKeys 요 아이를 어떻게 쓰느냐?
→ 예를 들어 json 파일에는 foundingdate 이렇게 되어 있는데, swift에서는 언더바() 형식의 네이밍을 변수에서 안씀. 규칙에 위배됨?!
→ 그래서 json에서는 founding_date로 돼있지만, foundingYear로 바꿔서 쓰겠습니다~ 요런 느낌?!
struct Landmark: Codable {
var name: String
var foundingYear: Int
var location: Coordinate
var vantagePoints: [Coordinate]
enum CodingKeys: String, CodingKey {
case name = "title"
case foundingYear = "founding_date"
case location
case vantagePoints
}
}
Encode and Decode Manually
Decodable를 extension 할때는 init 해주기
extension Coordinate: Decodable {
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
latitude = try values.decode(Double.self, forKey: .latitude)
longitude = try values.decode(Double.self, forKey: .longitude)
let additionalInfo = try values.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
elevation = try additionalInfo.decode(Double.self, forKey: .elevation)
}
}
Encodable 프로토콜을 extension하고 싶으면 encode(to:) 메소드를 써주면 됨
extension Coordinate: Encodable {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(latitude, forKey: .latitude)
try container.encode(longitude, forKey: .longitude)
var additionalInfo = container.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
try additionalInfo.encode(elevation, forKey: .elevation)
}
}
출처