티스토리 뷰

안녕하세요 :) Zedd입니다.

< 최신버전 확인하기 / App Udpate >글쓰다가 갑자기 Codable 개삘

Swift4가 나오기전에, JSON 파싱이 Swift4에서는 한줄로 끝난단다 하는 유튜브 영상을 봐서 오옷했던 기억이 있네요.

그 영상은 < Parsing JSON Just Became Super Easy in Swift 4 with Decodable >

Codable을 안써본 사람들도 있을거에요!

저도 아직 제대로 안써봄 ㅎ 

오늘 제대로 써봅시다.



Codable



자..Codable거리는데 도대체 Codable이 모냐

Codable이 정의부터 알고갑시다.



Codable의 정의를 보니 


"A type that can convert itself into and out of an external representation."

자신을 변환하거나 외부표현(external representation)으로 변환할 수 있는 타입입니다.


(외부표현(external representation)이라고 하는게 맞는건지..그리고 외부표현?이게 뭐야? 하실 수도 있는데 JSON같은거라고 생각하시면 됩니다.)


그러니까 아직 뭔지는 모르겠는데 Codable은 뭔가 변환해주는것 같네요. 

여기서 하나 재밌는 사실은


  1. typealias Codable = Decodable & Encodable



Codable은 이렇게 이루어져있답니다. 그럼이제 Decodable & Encodable이 뭔지 알아야함ㅎ



프로토콜이네요!!!

< Protocol (4) >글을 읽고오셨다면 Decodable & Encodable이 뭘 의미하는지 이제 감이 오실거라고 생각해요 :)

키키

그럼 Codable은? Decodable과 Encodable프로토콜을 준수하는 타입(프로토콜)이다!! 라고 할 수 있겠네요.

그럼 의미도 알았으니 Decodable과 Encodable이 각각 뭐하는 애들인지 봅시다.

Decodable : 자신을 외부표현(external representation)에서 디코딩 할 수 있는 타입

Encodable : 자신을 외부표현(external representation)으로 인코딩 할 수 있는 타입

이라고 하네요 XD...


자꾸 외부표현 외부표현 그러는데 헷갈리시면 JSON이라고 생각하시면 돼요!!!




오늘 할것도 Codable로 JSON파싱하고 그런거 할 거라서..


그럼 제일 최대의 궁금증

어떻게하는데??

자.. Codable은 프로토콜이죠? 그럼 어딘가에서 "채택"을 할텐데 어디서 채택을 할 수 있을까요?

아주 착하게도 ㅎ Class, Struct, Enum에서 모두 사용할 수 있답니다 :)

Codable을 채택했다는 의미는 Class, Struct, Enum을 serialize / deserialize할 수 있다는 것을 의미해요. 이 말뜻은 예제를 볼 때 이해가 가실겁니다.


그럼 간단한.....아주..간단한...Struct를 만들어볼까요?


  1. struct Person{

        var name : String

        var age : Int

    }




Codable이 뭐다? 

프로토콜 ㅇㅇ

채택 ㄱㄱ



  1. struct Person : Codable {

        var name : String

        var age : Int

    }


Codable을 채택했다는 뜻은... Decodable과 Encodable을 둘다 채택한 것과 마찬가지..

그럼 이제 Codable을 채택한 Person은 어떻게 될까요? 

"A type that can convert itself into and out of an external representation"

자신을 변환하거나 외부표현(external representation)으로 변환할 수 있는 타입.


외부표현식으로 변환할 수 있다네요. 외부표현식 == JSON이라고 가정했을 때,

JSON으로 변환 할 수 있다네요 == JSON으로 만들 수 있다네요.

즉 Person을 JSON으로 어케만드냐? 


  1. let encoder = JSONEncoder()



먼저 encoder를 하나 선언해줍니다. 이름만봐도 JSON으로 만들어줄 것 같이 생겼죠? JSONEncoder말고도




PropertyListEncoder도 있답니다. 저거는 딱 봐도 PropertyList로 변환시켜주는 encoder겠죠?


  1. let zedd = Person(name: "Zedd", age: 100)


그리고 Encode하고 싶은 Person타입의 인스턴스를 하나 만들어줍니다.

이제 대망의....Encode


  1. let jsonData = try? encoder.encode(zedd)


우리가 방금 zedd라는 Person타입의 인스턴스를 하나 만들었죠? 그걸 encoder의 encode메소드에 넣어줬네요.

이 encode메소드는 아무나 encode해주지 않습니다.




저~~번에 배운 Generic.

T는, 즉 encode안에 올 수 있는 값은 Encodable을 준수하고 있는 타입이어야 하네요.

우리 준수하나요?

Codable =  Decodable & Encodable

우리는 Codable만을 채택했지만 둘다 채택해준거나 다름없죠?

즉, Person타입의 인스턴스는 모두 Encodable을 준수하게됩니다.

그리고 encode 정의 옆에 throws라고 되어있는 것 보이시죠? encoding중에 에러를 발생시킬 수 있기때문에 반드시 try와 함께써주셔야 합니다 :)

그럼 이제 끝????은 아니고...

encode메소드의 리턴타입을 보시면 Data죠?

우리는 zedd인스턴스의 데이터를 얻은거고!!

이 Data를 예쁘게 해주면..!!


  1. if let jsonData = jsonData, let jsonString = String(data: jsonData, encoding: .utf8){

        print(jsonString) //{"name":"Zedd","age":100}

    }


if let으로 해준 이유는

1. try?로 해주었기때문에 jsonData가 Optional

2. String(data: , encoding: )의 리턴타입이 String?. 즉 Optional.


아무튼 JSON이 만들어졌습니다!!!!! 

그런데 우리가 보통 보던 JSON은 


  1. {

        "name" : "Zedd",

        "age" : 100

    }



이렇게생겼는데...이렇게 만들어줄 수 는 없어? {"name":"Zedd","age":100} 말고..

있습니다!!


  1. encoder.outputFormatting = .prettyPrinted


위 한줄만 추가해주면 정말 이름 그대로 Pretty하게 프린트가 됩니다. 키키 outputFormatting에는 


  1. encoder.outputFormatting = .sortedKeys


도 있는데요! 이름만보면 Key로 정렬한다? 맞습니다. 결과는 어떻게 나올까요? 


  1. {"age":100,"name":"Zedd"}


원래 name이 먼저였는데, age가 name보다는 알파벳적으로??...앞에 있으니 age가 먼저 나온것을 볼 수 있습니다.

prettyPrinted로는 설정되지 않았으니 예쁘게?(위에서 prettyPrinted로 설정했을 때 처럼) 나오진 않네요. 

나는 Key순으로 정렬도 하고싶고 예쁘게도 출력하고싶은데;;


  1. encoder.outputFormatting = [.sortedKeys, .prettyPrinted]


    {

        "age" : 100,

        "name" : "Zedd"

    }


이렇게 하시면됩니당 :)

전체코드도 넣을게요!



아무튼 이렇게 JSON을 만드는!!!! JSONEncoder에 대해서 알아봤어요.

하지만 여기까지 관심이 1도 없는 분들도 계실거에요. 왜냐? 우리는 파싱을 더 많이하거든

즉, Decoding을 더 많이하거든요.


그럼 뭔가 JSONDecoder를 사용해야할 것 만 같은 느낌이 들죠?

그 전에 JSON이 하나 있어야 Decoding을 하든 말든 하겠죠?

우리가 Decode해줄 JSON은 위에서 만든 jsonString으로 할게요.


  1. {

        "name" : "Zedd",

        "age" : 100

    }


이거 ㅎㅎ (outputFormatting을 하나도 적용하지 않은거로 할게요)

그럼 이제 위 JSON을 Decoding해봅시다.

그 전에, 우리가 Encoding을 어떻게 했냐?????를 보면 Decoding도 정말 쉬울거에요.

JSON. 어떻게 만들었죠?


1. JSONEncoder선언

2. 위 JSONEncoder의 encode메소드를 사용하여 인스턴스를 Data타입으로 만듬

3. Data타입을 String타입으로 만듬


이었죠?

그럼 거꾸로 하면 JSON이 Decode될 것 같지 않나요?


1. JSONDecoder선언

2. 우리의 JSON. 즉 String타입을 Data타입으로 만듬

3. Data타입을 JSONDecoder의 decode메소드를 사용하여 인스턴스로만듬


이 될 것 같네요. 해봅시다.


  1. let decoder = JSONDecoder()


JSONDecoder객체를 하나 만들고, 이제 우리의 JSON을 Data로 만듭시다.


  1. var data = jsonString.data(using: .utf8)


JSONDecoder의 decode메소드를 사용하여 data -> 인스턴스


  1. if let data = data, let myPerson = try? decoder.decode(Person.self, from: data) {

        print(myPerson.name)//Zedd

        print(myPerson.age)//100

    }


자..역시나 encode와 같은 이유로 if let으로 바인딩해주었어요.

위 코드에서 가장 낯선건 바로 Person.self라는 코드일테네요.

decode 코드의 원형은



입니다. 저 Person.self가 들어간 자리가 type:의 자리네요.

이 type은 "Decode할 값의 타입"이에요. 해당 type은 Decodable을 준수해야하구요. 우리가 JSON으로 만들고 싶은 최종적인게 우리의 Person타입이죠? 그래서 Person.self를 넣어준거에요.

우리 맨날 어떻게 했어요...


  1. var person = Person()

    if let personDictionary = response  {

        person.name = personDictionary["name"] as? String

        person.age = personDictionary["age"] as? String

    }


jsonserialization써서 Foundation객체로 만들고..Dictionary로 해서..해당 Key값 불러와서 내 인스턴스 프로퍼티에 대입하고..이랬죠??이랬던 과정을!!!!!!


  1. try? decoder.decode(Person.self, from: data)


이 한줄로 끝낼 수 있는겁니다. 우왕굳

Decoding전체코드도 첨부할게요 :)



어떠신가요 ㅎㅁㅎ

왜 Codable그러는지 알겠죠? :)

Codable이 내용이 많아서..나눠서 쓸려고해요!

아무튼 오늘도 도움이 되었으면 좋겠습니다 :)

2018년의 첫 주말이네요!! 행복하게 보내시길 바랄게요 ㅎㅎ

궁금한 점은 언제든지 댓글이나 PC화면 오른쪽 하단에 있는 채널서비스를 이용해서 질문주세요!!!


출처 :

https://medium.com/@Lukaz32/swift-4s-codable-protocol-b851b5b5cbd9

https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types




'Swift' 카테고리의 다른 글

Swift ) Inheritance(상속)  (7) 2018.01.15
Swift ) Access Control(접근 제어) - (1)  (4) 2018.01.13
Swift ) 왕초보를 위한 Codable / JSON Encoding and Decoding  (8) 2018.01.06
Swift4 ) Swap / Law of Exclusivity  (0) 2017.12.21
Swift ) Protocols (4)  (3) 2017.12.17
Swift ) Protocols (3)  (1) 2017.12.15
댓글
  • 프로필사진 yutae https://github.com/quicktype/quicktype-xcode

    이거랑 같이쓰면 더 좋을거에요 :)
    항상 화이팅 입니다 제드님 !!
    2018.02.20 13:38
  • 프로필사진 Favicon of https://zeddios.tistory.com BlogIcon Zedd0202 유태님XD감사합니다!! 퀵타입 스타만 눌러놓고 써보지는 않았었는데..한번 써볼게요!! 2018.02.20 23:07 신고
  • 프로필사진 Favicon of https://linsaeng.tistory.com BlogIcon Clover(린생) 안녕하세요 제드님 글을 읽다가 궁금한 점이 있어서 글을 남깁니다. "if let으로 바인딩해주었어요."라는 글이 있는데 바인딩의 뜻이 정확하게 궁금해서 글을 남겨봅니다. 제가 이해하기로는 바인딩은 값을 복사해서 쓰는게 아니라 참조값을 가지고 연결하는것을 말하는것으로 이해하고 있는데 제가 제대로 이해한것인지 궁금합니다. 즉 struct처럼 값을 복사하는게 아니라 class처럼 참조값을 복사하여 사용하는 것을 말하는것으로 이해해도 될까요? 2018.11.02 11:25 신고
  • 프로필사진 Favicon of https://zeddios.tistory.com BlogIcon Zedd0202 안녕하세요. 저는 저기서 "옵셔널 바인딩"의 의미로 사용한 바인딩인데.. Swift공식문서 https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html의 optional binding을 참고해주세요.
    2018.11.02 11:44 신고
  • 프로필사진 Favicon of https://inthechaos.tistory.com BlogIcon 하연화 http://genesis8.tistory.com/56

    바인딩이란 참조값을 연결한것뿐만아니라 여러가지 의미가 있습니다.
    2018.11.02 12:46 신고
  • 프로필사진 Favicon of https://linsaeng.tistory.com BlogIcon Clover(린생) zedd님,하연화님 감사합니다. ㅠㅠ 2018.11.02 14:34 신고
  • 프로필사진 Favicon of https://2donny-world.tistory.com BlogIcon 2donny 감사합니다 Zedd님~~ 2020.02.10 12:44 신고
  • 프로필사진 Favicon of https://memohg.tistory.com BlogIcon HyeonGyu IM 이해하기 쉬운 정리 감사합니다 2020.10.13 22:52 신고
댓글쓰기 폼
Total
3,260,910
Today
539
Yesterday
1,782