JSONSerialization — JSON을 Foundation 객체로 변환하고 그 역을 수행하도록 설계된 Foundation 프레임워크의 빌트인 iOS 클래스입니다. 이 API는 서드파티 라이브러리 없이 Apple 플랫폼에서 JSON을 작업하는 기본 메커니즘으로, 딕셔너리, 배열 및 원시 타입의 파싱을 지원합니다. Apple Developer, 2024에 따르면, JSONSerialization은 유연한 JSON 데이터 처리를 위해 Data, 스트림 및 읽기 옵션을 사용하는 것을 지원합니다.
주요 포인트
JSONSerialization은 iOS, macOS, tvOS 및 watchOS에서 사용 가능한 Foundation 프레임워크의 클래스입니다. JSON Data를 Foundation 객체(NSDictionary, NSArray, NSString, NSNumber)로 변환하고 그 역을 수행하는 메서드를 제공합니다. 이 클래스는 iOS 5에서 등장하였고 Codable(Swift 4)이 도입되기 전까지 Apple 플랫폼에서 JSON을 작업하는 기본 방법으로 남아 있었습니다. 오래된 클래스임에도 불구하고, JSONSerialization은 레거시 Objective-C 프로젝트와 고정된 모델 스키마 없이 동적적인 JSON 처리가 필요한 시나리오에서 여전히 중요합니다.
Codable의 등장에도 불구하고 JSONSerialization은 여러 시나리오에서 중요립니다. 동적적인 JSON 구조 — 응답 형식이 변경되거나 사전에 알 수 없는 경우 — 키를 통해 딕셔너리에 접근해야 하며, JSONSerialization을 통하는 것이 더 쉽습니다. 이 클래스는 Codable을 사용할 수 없는 Objective-C 프로젝트와 큰 JSON 파일의 점진적 파싱을 위한 스트림 작업에서도 사용됩니다. 테스트와 목업에서 isValidJSONObject와 data(withJSONObject:options:)를 사용하면 서드파티 라이브러리 없이도 JSON 픽스처를 빠르게 생성할 수 있어 개발과 프로토타이핑을 가속합니다.
import Foundation
// JSONSerialization 사용의 기본 구조
let jsonString = """
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
"""
guard let jsonData = jsonString.data(using: .utf8) else {
return
}
do {
let json = try JSONSerialization
.jsonObject(with: jsonData,
options: .mutableContainers)
print(json)
} catch {
print("JSON 파싱 오류: \(error)")
}
JSONSerialization은 JSON 작업을 위한 네 가지 주요 메서드를 제공합니다. 주요 메서드는 jsonObject(with:options:)로, Data를 Foundation 객체로 변환합니다. data(withJSONObject:options:) 메서드는 역 시리얼라이제이션을 수행합니다. isValidJSONObject(_:)는 객체가 시리얼라이즈될 수 있는지 확인합니다. writeJSONObject(_:to:options:error:)는 JSON을 스트림에 바로 쓰기 합니다. InputStream에서 JSON을 읽는 경우, Data 대신 스트림을 받는 jsonObject(with:options:) 메서드가 있어 스트리밍 데이터를 반환하는 네트워크 요청과 통합할 때 편리합니다.
jsonObject 메서드는 Data를 받고 Any(보통 NSDictionary 또는 NSArray)를 반환합니다. 안전한 사용을 위해 결과를 조건부 캐스팅으로 기대되는 타입으로 변환합니다. data 메서드는 Foundation 객체를 받고 JSON 표현이 있는 Data를 반환합니다. .prettyPrinted 옵션은 가독성을 위해 들여쓰기가 있는 ᇭ리맰을 추가합니다.
let jsonString = """
{
"products": [
{"id": 1, "name": "iPhone", "price": 999},
{"id": 2, "name": "iPad", "price": 799}
]
}
"""
let data = Data(jsonString.utf8)
if let json = try? JSONSerialization
.jsonObject(with: data) as? [String: Any],
let products = json["products"] as? [[String: Any]] {
for product in products {
if let name = product["name"] as? String {
print("제품: \(name)")
}
}
}
// 역 시리얼라이제이션: 객체 -> JSON
let outputDict: [String: Any] = ["status": "ok", "count": 42]
if let outputData = try? JSONSerialization
.data(withJSONObject: outputDict,
options: .prettyPrinted) {
String(data: outputData, encoding: .utf8)
}
기본 파싱 원시 타입의 딕셔너리는 JSONSerialization에서 가장 일반적인 작업입니다. URLSession을 통해 Data를 받은 후, 개발자가 jsonObject를 호출하고 결과를 기대되는 타입으로 캐스트합니다. 객체의 배열인 경우 [[String: Any]]로 캐스팅한 후 각 요소를 루프에서 처리합니다. 이 접근 방식은 유연하짠만 수동적인 타입 관리가 필요합니다.
실제 API는 배열, 날짜 및 선택적 필드가 있는 복잡한 중첩 JSON 객체를 반환합니다. JSONSerialization은 어떤 중첩 깊이도 올바르게 처리하지만 개발자가 각 레벨을 필요한 타입으로 독립적으로 캐스트해야 합니다. 이 작업을 간소화하기 위해 Apple은 타입화된 데이터에는 Codable을, 동적 구조에만 JSONSerialization을 사용할 것을 권장합니다.
// API 응답 파싱
func parseUserResponse(data: Data) {
do {
guard let json = try JSONSerialization
.jsonObject(with: data) as? [String: Any]
else { return }
guard let userId = json["id"] as? Int,
let name = json["name"] as? String
else {
throw ParsingError.missingField
}
print("사용자: \(name) (ID: \(userId))")
} catch let error as ParsingError {
print("파싱 실패: \(error)")
} catch {
print("예기치 않은 오류: \(error)")
}
}
enum ParsingError: Error {
case missingField
case invalidType
}
JSONSerialization은 유효하지 않은 JSON, 타입 불일치 또는 중첩 깊이 초과 시 오류를 발생시킵니다. 오류는 CocoaError 타입에 속하며 문제를 설명하는 코드를 포함합니다. 개발자는 do-catch 구문으로 이를 처리해야 하며, 그렇지 않으면 애플리케이션이 괴참됩니다. 가장 일반적인 오류는 NSPropertyListReadCorruptError(유효하지 않은 JSON)와 NSPropertyListReadUnknownError입니다. 각 오류 유형에는 고유한 처리 전략이 필요합니다. 유효하지 않은 형식의 경우 데이터 재전송을 요청하고, 구조 불일치의 경우 파싱 모델을 업데이트합니다.
유효하지 않은 JSON — 실패의 가장 일반적인 원인: 누락된 쉼표, 추가 문자 또는 이스케이프되지 않은 따옴표가 전체 파싱을 괴녑니다. 두 번째 유형은 기대된 구조와의 불일치입니다. 예를 들어 서버가 딕셔너리 대신 배열을 반환한 경우입니다. JSONSerialization.fragmentsAllowed는 루트가 딕셔너리나 배열이 아니라 원시 값인 JSON을 읽도록 허용합니다. JSON에 티어 레벨이 너무 많은 경우 개발자는 중첩 깊이 초과 오류를 마주챠으지도 합니다.
JSONSerialization은 파싱을 구성하는 여러 옵션을 제공합니다. .mutableContainers는 불변 버전 대신 NSMutableDictionary와 NSMutableArray를 반환하여 파싱 후 데이터 수정에 유용합니다. .mutableLeaves는 문자열 값을 변경 가능하게 만듭니다. .fragmentsAllowed는 루트가 객체나 배열이 아니라 문자열 또는 숫자인 JSON을 허용하여 간단한 API 응답에 편리합니다. .withoutEscapingSlashes와 .sortedKeys 옵션은 data(withJSONObject:options:) 메서드에 사용 가능하며, 시리얼라이즈된 JSON의 ᇭ리맱을 제어합니다. 옵션은 비트마스크로 전달되며, | 연산자를 통해 여러 값을 결합하여 유연한 파싱 구성이 가능합니다.
// 다양한 유형의 오류 처리
func safeParse(jsonData: Data) {
do {
let object = try JSONSerialization
.jsonObject(with: jsonData,
options: .fragmentsAllowed)
if let dictionary = object as? [String: Any] {
print("\(dictionary.count)개 키의 딕셔너리")
} else if let array = object as? [Any] {
print("\(array.count)개 항목의 배열")
}
} catch CocoaError.propertyListReadCorrupt {
print("기기된 JSON 데이터")
} catch let error as CocoaError {
print("Cocoa 오류: \(error)")
} catch {
print("알 수 없는 오류: \(error)")
}
}
// 시리얼라이제이션 전 객체 유효성 확인
let testObject: [String: Any] = ["key": "value", "nested": ["a": 1]]
if JSONSerialization.isValidJSONObject(testObject) {
print("유효한 JSON 객체")
}
JSONSerialization의 성능은 데이터 크기와 호출 빈도에 따락니다. 작은 서버 응답의 단일 파싱에서는 차이가 근소하지만, 수십 메가바이트의 JSON을 처리하거는 루프에서 빈번한 호출을 처리할 때 타입 캐스팅의 오버헤드를 고려해야 합니다. JSONSerialization은 현재 스레드에서 동기적으로 작동합니다. 따라서 큰 문서의 경우 DispatchQueue.global()을 통해 파싱을 백그라운드 큐로 옮길 것을 권장합니다. 대체로 InputStream을 사용하여 전체 파일을 메모리에 로드하지 않고 스트리밍 처리할 수 있으며, 이는 제한된 리소스를 가진 애플리케이션에 중요합니다. JSON을 파일 또는 네트워크 스트림에 쓰기 위해 writeJSONObject(_:to:options:error:) 메서드를 사용하면 중간 Data 객체를 생성하지 않고 바로 OutputStream으로 시리얼라이즈된 데이터를 보낼 수 있어 큰 문서를 작업할 때 메모리 소비를 줄입니다.
자주 묻는 질문
JSONSerialization은 JSON Data를 Foundation 객체(NSDictionary, NSArray)로 변환하고 그 역을 하는 Foundation 클래스입니다. 추가 라이브러리 없이 iOS, macOS, tvOS 및 watchOS에서 작동합니다.
Codable은 타입 안전한 코드로 컴파일되는 자동 타입 시리얼라이제이션을 위한 Swift 프로토콜입니다. JSONSerialization은 동적 Any 타입으로 작동하며 수동 캐스팅이 필요합니다. 새 프로젝트에는 Codable이, Objective-C와 동적 데이터에는 JSONSerialization이 적합합니다.
jsonObject를 호출할 때 do-catch 구문을 사용하십시오. JSONSerialization 오류는 CocoaError에 속합니다. 디버그시 NSPropertyListReadCorruptError를 확인하세요. 이는 유효하지 않은 JSON 데이터 형식을 나타냅니다.
네, JSONSerialization은 딕셔너리와 배열의 모든 중첩 깊이를 지원합니다. 모든 중첩 객체는 해당 Foundation 타입(NSDictionary, NSArray, NSString, NSNumber)으로 변환되어 원본 JSON 구조를 유지합니다.
JSONSerialization은 동적 JSON 구조, Objective-C 프로젝트, 스트림 작업 및 isValidJSONObject를 통한 JSON 검증에 적합합니다. 알려진 스키마가 있는 타입화된 구조에는 Codable이 더 좋습니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.