난 처음 디코딩과 Codable, 그리고 인코딩에 대해 공부할 때 뭐부터 해야할지도 모르겠고 왜 해야하는지 몰랐다.
우선 순서는 디코딩과 인코딩의 개념을 먼저 이해한 후 이후에 Codable에 대해 공부하려고 하는데, 왜냐고 한다면 그냥 자연스러운 순서라고 한다.
아니 자연스러운 순서도 순서지만, 실은 Codable이 디코딩과 인코딩의 기본적인 흐름 위에 설계된 도구이기 때문이다.
우선 기본 개념에 대한 이해가 필요하니 설명하자면,
디코딩은 데이터를 "읽어서 객체로 변환" 하는 과정이고,
인코딩은 객제를 "저장하거나 전송 가능한 데이터로 변환" 하는 과정이다.
ex)
- JSON 문자열 --> Swift 객체 =
디코딩
- Swift 객체 --> JSON 문자열 =
인코딩
이제 여기서부터 동작 원리에 대해 파악을 해보자면,
Codable은 디코딩과 인코딩을 더 쉽게 만들어주는 하나의 프로토콜이라고 보면 된다.
이 과정의 작동 원리도 모른 채 Codable을 사용한다면,
내부적으로 무슨 일이 일어나는지 알기 어려우니 문제가 생길 때 해결하기가 힘들 것이다.
Codable이 아닌 다른 방식도 존재하긴 하다.
꼭 Codable만 사용할 필요는 없긴하고,
JSONSerialization
이라는 다른 도구도 있다고 한다.
공식문서링크
위에서 말한 도구는 디코딩과 인코딩 자체를 먼저 알면 다양한 방법을 비교하면서 적절히 사용할 수 있다.
디코딩과 인코딩의 과정을 굳이 거치는 이유가 궁금한 사람도 있겠지.
그게 바로 나다.
그래도 날씨어플을 만들기 전 공부하는 이유가 있겠거니 하고 강의를 듣고 있던 중,
이렇게 의도도 모른채로 공부했다가는 절대 머리에 들어오지 않을 것 같다는 생각에 폭풍검색을 했다.
.
.
그렇게 알게 된 정보로는 디코딩과 인코딩을 거치는 이유가
서로 다른 데이터 표현방식 때문에 앱과 외부 데이터간의 소통을 가능하기 위함이라고 한다.
외부 데이터
란 파일이나 서버, 네트워크를 말하는건데, 이것들은 앱이 데이터를 읽고 쓰는데 필요한 기본적인 과정이기 때문이다.
Struct
, Class
)JSON
, XML
또는 이진데이터
의 형식으로 저장되거나 전달된다.그 두 가지가 바로 디코딩과 인코딩이다.
디코딩과 인코딩은 데이터를 표준 형식으로 바꿔서 다른 시스템과 호환되도록 한다.
만약 사용자가 앱에서 만든 데이터를 서버에 저장하려고 한다면,
객체 데이터를 JSON형식으로 인코딩 해야 서버가 이해할 수 있고,
서버에서 JSON 데이터를 받으면, 앱이 사용할 객체로 디코딩해야 화면에 표시할 수가 있다는 것이다.
자세히 설명을 더 해보자면,
앱 -> 서버로 데이터 전송 시
앱은 주로 swift로 작성되고 데이터는 객체 형태로 관리가 된다.
예를 들어 (User(name: "sonny", age: "25"))
이런식으로 말이다.
하지만 서버는 swift를 이해하지 못할 수 있다. (처음엔 차별하는 줄 알았다) 서버는 파이썬이나 자바,루비 등으로 작성될 수 있기 때문에 앱의 내부 데이터 구조를 그대로 처리할 수가 없다.
그래서 이 swift 데이터를 서버가 이해할 수 있는 표준형식인 JSON으로 변환을 해야 하는 과정이 필요한데 이것이 인코딩이다.
만약 JSON으로 위 내용이 변환된다면,
{"name": "sonny", "age": 25}
이렇게 인코딩이 되고 이제 서버는 이 JSON 데이터를 쉽게 읽을 수 있게 된다.
서버에서 데이터처리
서버는 JSON 데이터를 받고 이걸 자기가 사용하는 언어에 맞는 형태로 디코딩을 한다.
만약 파이썬 서버라면, JSON 데이터를 받을 경우 파이썬의 딕셔너리로 알아서 변환해 처리하게 된다.
서버 -> 앱으로 데이터 전송
서버는 데이터를 처리하고 나서 앱을 보낼 때 다시 JSON 형식으로 변환한다 (인코딩)
어차피 JSON은 언어와 플랫폼에 상과없이 공통적으로 이해할 수 있는 형식이기 때문이다.
앱에서 데이터 사용
앱은 서버에서 받은 JSON 데이터를 디코딩해서 swift 객체로 변환한다.
이렇게 변환된 데이터를 이제 화면에 표시하거나 내부 로직에서 사용할 수 있게 된다.
디코딩과 인코딩 과정에서 데이터 타입과 값의 유효성을 검사하게 된다.
그 이유는 혹여라도 잘못된 데이터가 앱에 전달되거나 처리하는걸 방지하기 위함인데,
이건 앱의 안전성과 안정성을 유지하는데 아주 중요하다고 한다. (라임 장난 아니다)
디코딩과 인코딩 과정에서 데이터 타입과 값의 유효성을 검사하는 이유는, 잘못된 데이터가 애플리케이션에 전달되거나 처리되는 것을 방지하기 위해서이다. 이는 앱의 안전성과 안정성을 유지하는 데 매우 중요한 역할을 한다. 하나씩 구체적으로 살펴보겠다.
서버에서 보내는 JSON 데이터가 앱의 모델(Swift 객체)에 매핑이될 때,
JSON 데이터와 Swift의 데이터 타입이 정확히 일치해야 한다.
서버에서 이런 JSON 데이터를 보냈다고 생각해보자.
{
"name": "Alice",
"age": "25" // 나이가 숫자가 아니라 문자열로 표현이 되어버림.
}
앱에서 다음과 같은 Swift 모델로 이 JSON을 디코딩하려고 한다면?
struct User: Codable {
let name: String
let age: Int
}
여기서 age
는 Int
로 정의되었지만, 서버에서 age
를 문자열로 보냈다.
이 경우에는
age
값을 Int
로 변환하려 시도한다.do-catch
구문으로 처리할 수 있다.이렇게 타입 검사를 통해 부정확한 데이터가 앱에 들어오는 것을 방지할 수 있다.
서버에서 JSON 데이터를 보냈지만 일부 필드가 누락되었다고 생각해보자.
{
"name": "Alice"
// "age" 필드가 없음
}
그리고 Swift는 다음과 같다고 한다면,
struct User: Codable {
let name: String
let age: Int
}
여기서 age
필드가 필수인데, 해당 데이터가 없으면
만약 age
필드가 선택적(Optional
)로 정의되었다면
struct User: Codable {
let name: String
let age: Int?
}
age
필드가 없으면 nil
로 처리된다.서버가 다음과 같은 JSON 데이터를 보냈다고 생각해보자.
{
"name": "Alice",
"age": 25,
"invalid_field": "unexpected" // 예상하지 못한 필드
}
Swift 코드
struct User: Codable {
let name: String
let age: Int
}
여기서는
invalid_field
는 Swift 모델에 정의되지 않았으므로 디코딩 중 무시된다.디코딩 중 발생한 에러는 앱이 적절히 처리할 수 있다.
do {
let user = try JSONDecoder().decode(User.self, from: jsonData)
print("디코딩 성공: \(user)")
} catch {
print("디코딩 실패: \(error.localizedDescription)")
}
이런 방식으로
앱 안정성 보장
잘못된 데이터로 인해 앱이 크래시하거나 오작동하지 않도록 예방할 수 있음.
사용자 경험 향상
데이터를 미리 검증하고 처리할 수 있기 때문에, 사용자에게 정확한 정보와 예측 가능한 동작을 제공할 수 있다.
개발자의 디버깅 편의성
에러를 명확히 인식하고 처리할 수 있어서 문제를 쉽게 추적하고 수정할 수 있다.
정리하자면,,
디코딩 과정은 데이터 타입과 값을 자동으로 검사하고 오류가 발생하면 이것을 처리할 수 있는 기회를 제공한다.
이런 과정을 거쳐 앱이 안전하고 신뢰할 수 있는 방식으로 데이터를 처리하게 만들어 주는 것이고,
이것이 인코딩과 디코딩 과정이 앱에서 중요한 이유다.
앞서 Codable
을 이해하기 위해 인코딩과 디코딩을 이해했으니 Codable를 배울 차례이다.
Codable은 Swift에서 인코딩(encoding)과 디코딩(decoding)을 쉽게 처리할 수 있도록 설계된 프로토콜이다.
이건 Encodable
과 Decodable
프로토콜을 결합한 타입인데,
데이터를 다른 포맷(JSON, Property List 등)으로 변환하거나,
반대로 데이터를 Swift 객체로 변환하는데 사용된다.
Codable을 사용하면 개발자가 별도의 작업 없이도 JSON, Property List 등의 데이터를 구조체(struct)나 클래스(class)에 손쉽게 매핑할 수 있다.
Codable
은 이 두 가지를 하나로 합친 프로토콜이다.
typealias Codable = Encodable & Decodable
간편함: 별도의 코드 작성 없이 기본 타입(문자열, 숫자 등) 및 사용자 정의 타입을 손쉽게 변환 가능.
표준적 데이터 처리: 서버와의 데이터 교환(JSON 등)이나 파일 저장(Property List 등)에 적합 함.
유지보수 용이: Swift 타입을 정의한 후 Codable을 채택하기만 하면 대부분의 변환 작업이 자동으로 처리 됨.
Codable을 채택한 구조체를 정의한다
struct User: Codable {
let name: String
let age: Int
}
JSON 데이터를 Swift 객체로 변환
let jsonData = """
{
"name": "Alice",
"age": 25
}
""".data(using: .utf8)!
do {
let user = try JSONDecoder().decode(User.self, from: jsonData)
print(user.name) // "Alice"
print(user.age) // 25
} catch {
print("Decoding failed: \(error)")
}
Swift 객체를 JSON 데이터로 변환
let user = User(name: "Bob", age: 30)
do {
let jsonData = try JSONEncoder().encode(user)
if let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
// 출력: {"name":"Bob","age":30}
}
} catch {
print("Encoding failed: \(error)")
}
Codable은 Swift의 키-값 컨테이너를 사용하여 데이터를 매핑한다.
만약 JSON 키와 프로퍼티 이름이 다르다면 CodingKeys
를 사용해 매핑을 커스터마이징할 수 있다.
struct User: Codable {
let userName: String
let userAge: Int
enum CodingKeys: String, CodingKey {
case userName = "name"
case userAge = "age"
}
}
복잡한 데이터 구조
유연성 부족
Decodable
이나 Encodable
을 구현해야 할 수 있다.Codable은 Swift에서 데이터를 디코딩하거나 인코딩할때 표준적이고 간편하게 처리할 수 있는 강력한 도구다.
실제로 Codable을 사용해보면 서버에서 데이터를 가져오거나 앱 데이터를 저장할 때의 편리함을 실감할 수 있기도 하고,
특히 JSON과 같은 일반적인 데이터 교환 포맷과 사용할 때 추가적인 코드 작성 없이도 매끄럽게 작동한다는 점이 큰 장점이다.
오늘 공부를 통해 데이터간의 변환하는 과정과 그것에 대한 중요성, 그리고 발생할 수 있는 다양한 문제들이 있다는 걸 알게 됐다.
아직 잘못된 타입이나 값의 누락에 대한 처리를 위해서 do-catch 구문을 사용하는게 헷갈라긴 하지만 그래서 더 실습이 필요하다는 것도 느꼈고,
실제 앱을 개발할 때 정말 필요하고 기본적인 기술이라는 생각이 들었다.
만약 서버와 앱간의 데이터를 주고받는 앱을 만든다면 더더욱 꼭 알아야 할 기술인 듯 싶다.
데이터에 표준 형식이 있다면 그걸 그냥 다같이 따르면 되지 왜 각자 스타일로 만들고 인코딩&디코딩 하는 걸까 했더니 안전성 확보 효과도 있군여