본 글은 이전([iOS] 네트워크 통신1 - URLSession)의 내용과 연결됩니다.
Codable
사용방법 뿐만 아니라URLsession
을 이용한 네트워크 통신까지 학습하고 싶은 분들은 이전 글을 참고하시면 됩니다.
잘못된 내용은 댓글로 알려주시면 감사하겠습니다.😎
codable
이란 무엇일까??
codable 공식문서
문서를 읽어보면.. 외부 타입으로 변환하거나 표현할 수 있는 하나의 타입
이라고 합니다.
여기서 말하는 외부 타입은 JSON
, XML
와 같은 데이터 전송 형식입니다. 즉 codable
이란 iOS에서 하나의 타입을 JSON
과 같은 데이터 전송 형식으로 서로 변환 해주는 것이라고 생각하면 됩니다.
codable
선언(Declaration)을 보면.. typealias
라는 용어가 사용됩니다.
typealias
는 새로운 타입을 하나의 별칭
으로 사용한다는 의미입니다. 여기서는 Decodable
과 Econdable
프로토콜 모두를 준수하는 타입(프로토콜을)을 Codable
이라는 별칭으로 사용한다고 프로그램에 알려줍니다.
결국 Codable
을 채택한다는 의미는 Decodable
과 Econdable
프로토콜을 동시에 채택한다는 의미가 됩니다.
그러면 Decodable
과 Encodable
프로토콜이 어떤 역할을 하는지 확인합시다.
Decodable과 Encodable프로토콜
이름 그대로 데이터
를 encode
, decode
해주는 프로토콜이네요.
그러면 Codable
을 채택하여 네트워크 통신을 통해 전송받은 JSON
데이터를 decode
해봅시다.
encode
에 관한 내용은 따로 다루지 않습니다.decode
의 반대 개념이기 때문에decode
만 이해한다면 쉽게 사용할 수 있습니다.
그러면 codable
한 타입을 만드는 간단한 방법은 무엇일까요?? 표준 라이브러리 타입(Int
, String
, Double
) 또는 Foundation 타입(Data,URL
) 등의 타입들을 사용하여 프로퍼티의 이름을 JSON
데이터의 키와 매칭 시켜주는 것입니다.
그리고 해당 프로퍼티를 사용하는 구조체, 클래스 또는 열거형을 선언하여 Codable
프로토콜만 채택하면 됩니다. 본 글에서는 구조체를 사용하겠습니다.
그러면 예시를 확인합니다.
만약 JSON
데이터가 아래와 같다면, 구조체를 어떻게 구현해야 할까요??
{
"name": "Banana",
"points": 200,
"description": "A banana grown in Ecuador."
}
단순히 JSON
데이터에 해당하는 키를 구조체의 프로퍼티로 사용하면 됩니다.
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
그리고 아래와 같이 decode
메소드를 호출해 주면 쉽게 디코딩 할 수 있습니다.
let decoder = JSONDecoder()
let food = try? decoder.decode(GroceryProduct.self, from: JSONData())
만약에 JSON
데이터의 키가 카멜 케이스 형식과 같이 swift의 변수나 상수로 사용할 수 없는 이름이면 어떻게 해야 할까요??
{
"product_name": "Banana",
"product_cost": 200,
"description": "A banana grown in Ecuador."
}
그럴 경우 CodingKey
프로토콜을 사용하여 문자열 타입의 대체키를 선언하면 됩니다.
CodingKey 프로토콜
CodingKey 프로토콜
이란 인코딩 또는 디코딩 하는 경우, 키로 사용되는 타입이라고 합니다. 이 프로토콜을 채택하는 열거형을 선언하여 case의 raw_value
에 대체키 이름을 할당하면 됩니다.
여기서 말하는 대체키는 JSON
데이터 키의 이름입니다.
name -> "product_name", cost -> "product_cost"로 대체키 사용
struct GroceryProduct: Codable {
var name: String
var cost: Int
var description: String?
enum CodingKeys: String, CodingKey {
case name = "product_name"
case cost = "product_cost"
case description
}
}
파싱한 JSON
데이터는 아래의 테이블 뷰에 사용할 예정입니다. (지금은 통신의 결과로 받은 데이터가 아닌 소스코드에 직접 입력한 모습.)
다음으로 디코딩 할 JSON
데이터를 확인해보겠습니다.
데이터를 보니.. 음..deep
합니다. hoppin
-> movies
-> movie
키 안에 우리가 원하는 영화의 이름, 이미지, 평점 등이 있네요.
이렇게 JSON
데이터가 복잡한 경우 위에서와같이 구조체를 구현하기 어려울 수 있습니다. 그럴 경우 좋은 사이트가 하나 있는데요. 이 사이트는 JSON
데이터의 형식에 맞도록 Codable
를 채택하는 구조체를 자동으로 구현해 줍니다. 링크
위 사이트에, 전송받을 JSON
데이터를 입력하면 아래와 같이 자동으로 Codable
프로토콜을 채택하는 구조체를 만들어줍니다.!!
이제 Codable
프로토콜을 채택하는 구조체를 만들었으니, decoder
를 만들고 전송받은 데이터 receivedData
를 디코딩 하면 됩니다.
전송받은 데이터인 영화정보가 movie
키의 배열에 저장되어 있기 때문에 지금은 예시로 제일 첫 번째 데이터만 출력합니다.
잘 출력되는 것을 확인할 수 있네요.. 이제 파싱한 데이터를 테이블 뷰에 적용합시다.
테이블에 뿌려줄 데이터를 저장할 프로퍼티 list
를 선언합니다. section
을 지정하지 않으니, 1차원 배열로 생성합니다.
다음으로 네트워크 통신의 결과로 받은 데이터를 디코딩
해야겠죠?? 메소드는 decode
를 사용하면 됩니다.
decode
메소드의 첫 번째 파라미터에는 decode
를 수행할 타입, 두 번째 타입에는 decode
할 데이터를 할당하면 됩니다. 물론 오류가 발생할 수 있으므로 try
를 사용합니다. JSON
데이터를 파싱 하였으니 함수 addTableData
를 호출합니다.
addTableData 함수
함수의 인자에 전달된 movelist
배열은 각 element에 영화의 정보를 담고 있습니다. for-loop
를 통해 각 element를 읽고 데이터 모델을 나타나내는 클래스 MovieVO
의 인스턴스를 생성하여 인스턴스의 프로퍼티에 전달받은 값을 할당하면 됩니다.
여기서 중요한 점은 tableView.reloadData()
부분인데요. UITableView
의 메소드인reloadData()
는 table view의 section과 row를 reload
합니다.
이 메소드를 호출하는 이유는 TableView
를 만들기 위해 사용되는 함수인 tableView(:numberOfRowsInSection:)
와 tableView(:cellForRowAt:)
등 보다 서버와의 통신이 느리기 때문입니다.
즉 테이블 뷰를 만드는 함수가 호출되는 시점에서, 테이블 뷰에 사용될 데이터가 아직 서버에서 전송되지 않았기 때문에 테이블 뷰를 만들 데이터가 없습니다. 그러면 빈 테이블이 생성되겠죠?? 그러므로 서버와의 전송이 끝난 후 각 section 및 row를 다시 load 하기 위해 호출합니다.
reload
를 사용하지 않고,notification
을 사용하는 방법도 존재합니다.
마지막으로 테이블 뷰의 각 row를 구성하기 위해 호출되는 함수인 tableView(_:cellForRowAt:)
메소드를 수정합니다.
대부분의 내용은 이전 글과 비슷하나 달라진 점이 1가지 있습니다. 이전까지는 프로젝트의 내부에 이미지를 저장하여 내부 저장소의 주소를 사용했습니다. 그러나 현재는 이미지의 주소가 url
형식이기 때문에 마찬가지로 서버와 통신을 해야 합니다.
이전처럼 delegate
를 지정할 수도 있지만 이미지를 가져오는 단순한 작업이기 때문에 shared
인스턴스를 사용하며, completion handler
로 결과를 받습니다.
이제 서버에서 불러온 이미지를 확인하겠습니다. 약 100개의 데이터를 테이블에 불러옵니다.
테이블 뷰에 전송된 데이터 적용 모습
프로젝트의 나머지 부분이 궁금하신 분들은
테이블뷰
,URLSession통신
관련 글을 참고하면 됩니다. 또한 전체소스코드는 깃허브에 있습니다.
지금 코드는 서버의 자료를 한 번에 로드합니다. 그러므로 다음 글에는 테이블 뷰의 성능 개선에 대한 내용을 작성할 예정입니다.
https://developer.apple.com/documentation/swift/codable
https://developer.apple.com/documentation/swift/codingkey
https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
https://developer.apple.com/documentation/foundation/archives_and_serialization/using_json_with_custom_types
https://developer.apple.com/documentation/uikit/uitableview/1614862-reloaddata
꼼곰한 재은씨의 swift 기본편