Swift

Swift :: Codable 알아보기

상어(shark) 2019. 2. 14. 18:41

안녕하세요! 상어입니다.

블로그에 쓰고싶은 소재는 많은데 정말정말 꾸준히 한다는게 어렵네요 ㅎㅎ;

많은 블로그님들 존경합니닷 😄


오늘은 Codable에 대해서 알아볼까 합니다.

swift4에서 나왔는데 저도 Codable에 대해 알고 난 이후부터는 Codable만 쓰네요.

넘나 편한것!!!!!


그럼 Codable을 알아보러 가볼까여?~


Codable


Codable은 Encodable과 Decodable이 합쳐진거랍니다.

여기서 Encodable과 Decodable이란,

Encodable -> data를 Encoder에서 변환해주려는 프로토콜로 바꿔주는 것

Decodable -> data를 원하는 모델로 Decode 해주는 것

입니다. 무슨 말인지 이해가 잘 안되신다구요?! 


json을 예로 들자면,

Encodable -> 모델을 json으로 인코드

Decodable -> json을 내가 원하는 모델로 디코드

한다고 생각하시면 이해하기 편하실거에요ㅎㅎ(물론 이건 하나의 예시에욧!!!)


Codable의 사용방법은 간단합니다.

Codable은 프로토콜이기 때문에 채택을 해야하는데 어디서 하느냐!

struct, enum, class 전부 채택 가능하답니다. 우오아아앙 


저는 Codable을 model에서 채택하는데, 지금부터 보여드릴 예제도 그와 비슷한 것이에욥.


우선, User라는 struct를 만듭니다. 


struct User { enum CodingKeys: String,CodingKey { case id case name case birth case phoneNum = "phone_num" }

let id: Int let name: String let birth: String let phoneNum: String }

여기서 enum CodingKeys는 뭐냐,

CodingKeys는 json key가 아닌 내가 원하는 이름으로 지정해줄 수 있게 해주는 프로토콜입니다.

위의 예제에서는 실제 json key들이 id, name, birth, phone_num이지만 제가 지정해주는 이름들로는 id, name, birth, phoneNum입니다.

만약, json key와 내가 지정하는 이름이 같다면 case에 json key만 작성하시면 됩니다.


여기까지가 decodable과 encodable의 공통사항이고, 이제부터는 따로 예시를 작성하겠습니다.


Decodable


아마 Codable을 사용하면서 가장 많이 쓰는건 Decodable일거라 생각합니다 ㅎㅎ

Decodable은 프로토콜이니까 User stuct에서 채택해주시면 됩니다.


extension User: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
        birth = try container.decode(String.self, forKey: .birth)
        phoneNum = try container.decode(String.self, forKey: .phoneNum)
    }
}

Decodable을 채택하면 무조건 init을 생성해야합니다.

위와 같은 형태는 애플 문서에 나와있는 형식입니다.

(참조) https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types


이렇게 Decodable을 채택한 후


func decode() {

let jsonString = """ [ { "id": 1, "name": "shark1", "birth": "1999-03-17", "phone_num": "010-2222-3333" }, { "id": 2, "name": "shark2", "birth": "1999-03-19", "phone_num": "010-2222-3334" }, { "id": 3, "name": "shark3", "birth": "1999-03-20", "phone_num": "010-2222-3353" } ] """ let jsonData = jsonString.data(using: .utf8) do {

guard let jsonData = jsonData else { return } let dataModel = try JSONDecoder().decode([User].self, from: jsonData) print(dataModel) } catch let error { print("에러 뿜뿜 : \(error)") } }

일단 

1) jsonString이라는 임의의 json형태인 string타입의 변수를 생성했습니다.

그리고 

2) decode를 하기 위해서는 Data타입이 필요하기 때문에 String타입을 Data로 변환시켜주었고,

3) JSONDecoder()을 이용하여 decode를 [User]타입에 맞게 한다면!


[Codable.User(id: 1, name: "shark1", birth: "1999-03-17", phoneNum: "010-2222-3333"),

Codable.User(id: 2, name: "shark2", birth: "1999-03-19", phoneNum: "010-2222-3334"),

Codable.User(id: 3, name: "shark3", birth: "1999-03-20", phoneNum: "010-2222-3353")]

쨔짜잔~ User 형태에 맞추어 decode가 되었습니다. 쨕쨖쨖!!!!!!

싱기하죠? 간단하죠??

Codable을 이용하면 단 몇줄만으로도 decode를 할 수 있다는 점!

그럼 Encodable은 Decodable의 반대로 하면 됩니다.


Encodable


extension User: Encodable {
    func encode(to encoder: Encoder) throws{
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)
        try container.encode(birth, forKey: .birth)
        try container.encode(phoneNum, forKey: .phoneNum)
    }
}

Decodable과 마찬가지로 Encodable을 채택한 후, 코드를 작성하면 됩니다.


func encode() { let userObject = User(id: 1, name: "shark1", birth: "2000-03-02", phoneNum: "010-3434-2222") do { let jsonData = try JSONEncoder().encode(userObject) let jsonString = String(data: jsonData, encoding: .utf8) guard let printJsonString = jsonString else { return } print(printJsonString) } catch let error { print("에러 뿜뿜 : \(error)") } }

decode할 때와는 반대로

1) userObject라는 객체를 만들고,

2) JSONEncoder의 encode메서드를 이용하여 Data타입으로 만든 후,

3) String 타입으로 만듭니다.


아까 decode할 때는 JSONDecoder()을 사용했는데, encode할 때는 JSONEncoder()을 사용하시면 됩니다. 그러면


{"id":1,"name":"shark1","birth":"2000-03-02","phone_num":"010-3434-2222"}

이와 같은 json형태가 출력이 됩니다.

우왕 이뻐요 멋져요 좋아요!!



이제 왜 Codable을 사용하는지 와닿으시나요??

저는 진짜 혁명이었습니다. 아닛! 이런게 있어?!!!하면서 우왕우왕했어옇ㅎㅎㅎ


추가로 User struct처럼 type이 이쁘게 다 지정되어있는 객체같은 경우에는


struct User: Codable {
    enum CodingKeys: String,CodingKey {
        case id
        case name
        case birth
        case phoneNum = "phone_num"
    }
    
    let id: Int
    let name: String
    let birth: String
    let phoneNum: String
}

Encodable, Decodable을 따로 채택하지 않고, Codable만 채택해서 축약할 수 있답니당~

Codable은 typealias Codable = Encodable & Decodable 이니까요!!

그치만 위에서 말씀드렸다시피 type이 다 지정되어있는 이이이쁜 아이들만 가능해요.

만약,

struct안에 struct가 있다거나, Any타입이거나, [String:Any]이거나 등등등인 친구들은 축약은 힘들다는 점!

유의하시면서 코딩하시면 될 듯해요 ㅎㅎㅎ


그럼 Codable에 대한 설명은 여기까지 할게욥😆


안뇽!