JSONSerialization — คลาส iOS ในตัวของเฟรมเวิร์ก Foundation ที่ออกแบบมาเพื่อแปลง JSON เป็นออบเจกต์ Foundation และกลับคืน API นี้เป็นกลไกพื้นฐานสำหรับการทำงานกับ JSON บนแพลตฟอร์ม Apple โดยไม่ต้องใช้ไลบรารีบุคคลที่สาม รองรับการแยกวิเคราะห์พจนานุกรม อาร์เรย์ และชนิดประถมภาษา ตามแหล่งข้อมูลจาก Apple Developer, 2024 ได้กล่าว้า JSONSerialization รองรับ การทำงานกับ Data, สตรีม และตัวเลือกการอ่านสำหรับการประมวลผลข้อมูล JSON แบบยืดหยุ่นได้
ประเด็นสำคัญ
JSONSerialization เป็นคลาสของเฟรมเวิร์ก Foundation ที่ใช้ได้บน iOS, macOS, tvOS และ watchOS ให้เมธอดในการแปลง JSON Data เป็นออบเจกต์ Foundation (NSDictionary, NSArray, NSString, NSNumber) และกลับคืน คลาสนี้ปรากฏตัวใน iOS 5 และจนกระทั่งที่ Codable (Swift 4) ถูกนำมาใช้ มันยังเป็นวิธีหลักในการทำงานกับ JSON บนแพลตฟอร์ม Apple แม้ว่าจะมีอายุมานาน แต่ JSONSerialization ยังคงมีความสำคัญในโปรเจกต์ Objective-C ดั้งเดิม และในสถานการณ์ที่ต้องการประมวลผล JSON แบบไดนามิกโดยไม่มีโครงสร้างโมเดลตายตัว
แม้ว่า Codable จะถูกนำมาใช้แล้ว แต่ JSONSerialization ยังคงมีความสำคัญในหลายสถานการณ์ โครงสร้าง JSON แบบไดนามิก — เมื่อรูปแบบการตอบสนองเปลี่ยนแปลงหรือไม่ทราบล่วงหน้า — ต้องการเข้าถึงพจนานุกรมโดยผ่านคีย์ ซึ่งทำได้ง่ายกว่าผ่าน JSONSerialization คลาสนี้ยังใช้ในโปรเจกต์ Objective-C ที่ Codable ไม่พร้อมใช้งาน และเมื่อทำงานกับสตรีมสำหรับการแยกวิเคราะห์ไฟล์ JSON ขนาดใหญ่แบบเพิ่มทีละน้อย ในการทดสอบและโมเดิ้ง isValidJSONObject และ data(withJSONObject:options:) ช่วยให้สามารถสร้าง JSON fixture ได้อย่างรวดเร็วโดยไม่ต้องใช้ไลบรารีบุคคลที่สาม ซึ่งเร่งการพัฒนาและการสร้างต้นแบบ
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 โดยตรงไปยังสตรีม สำหรับการอ่าน JSON จาก InputStream มีเมธอด jsonObject(with:options:) ที่รับสตรีมแทน Data ซึ่งสะดวกเมื่อรวมกับคำขอเครือข่ายที่ส่งกลับข้อมูลแบบสตรีม
เมธอด jsonObject รับ Data และคืน Any — โดยปกติ NSDictionary หรือ NSArray สำหรับการใช้งานที่ปลอดภัย ผลลัพธ์จะถูกแปลงเป็นชนิดที่คาดหวังโดยการแปลงแบบมีเงื่อนไข เมธอด data รับออบเจกต์ Foundation และคืน Data ที่มีการแสดงผลเป็น JSON ตัวเลือก .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 หลังจากรับ Data ผ่าน URLSession แล้ว นักพัฒนาจะเรียก 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 ไม่ถูกต้อง — สาเหตุที่พบบ่อยที่สุดของความล้มเหลว: จุลภาคที่ขาดไป, อักขระพิਞเศษ หรือเครื่องหมายอัญประกาศที่ไม่ได้ escape ทำให้การแยกวิเคราะห์ทั้งหมดล้มเหลว ข้อผิดพลาดประเภทที่สองคือความไม่ตรงกับโครงสร้างที่คาดหวัง: ตัวอย่างเช่น เซิร์ฟเวอร์ส่งกลับมาเป็นอาร์เรย์แทนพจนานุกรม JSONSerialization.fragmentsAllowed อนุญาตให้อ่าน JSON ที่รากไม่ใช่พจนานุกรมหรืออาร์เรย์ แต่เป็นค่าประถมภาษา นักพัฒนาอาจพบกับข้อผิดพลาดเกินความลึกของการซ้อนกันเมื่อ JSON มีระดับลำดับชั้นมากเกินไป
JSONSerialization ให้ตัวเลือกหลายอย่างสำหรับการกำหนดค่าการแยกวิเคราะห์ .mutableContainers คืน NSMutableDictionary และ NSMutableArray แทนเวอร์ชันที่ไม่สามารถเปลี่ยนแปลงได้ ซึ่งมีประโยชน์เมื่อแก้ไขข้อมูลหลังการแยกวิเคราะห์ .mutableLeaves ทำให้ค่าสตริงสามารถเปลี่ยนแปลงได้ .fragmentsAllowed อนุญาต JSON ที่รากไม่ใช่ออบเจกต์หรืออาร์เรย์ แต่เป็นสตริงหรือตัวเลข — สะดวกสำหรับการตอบสนอง API ที่ง่าย ตัวเลือก .withoutEscapingSlashes และ .sortedKeys ใช้ได้สำหรับเมธอด data(withJSONObject:options:) ควบคุมการจัดรูปแบบของ JSON ที่ถูกเสรียโอาลัย์ซ์ ตัวเลือกถูกส่งผ่าน bitmask ทำให้สามารถรวมค่าหลายค่าโดยใช้ตัวดำเนินการ | สำหรับการกำหนดค่าการแยกวิเคราะห์แบบยืดหยุ่น
// การจัดการข้อผิดพลาดหลายประเภท
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:) ช่วยให้สามารถส่งข้อมูลที่ถูกเสรียโอาลัย์ซ์ไปยัง OutputStream โดยตรงโดยไม่ต้องสร้างออบเจกต์ Data กลาง ซึ่งลดการใช้หน่วยความจำเมื่อทำงานกับเอกสารขนาดใหญ่
คำถามที่พบบ่อย
JSONSerialization เป็นคลาส Foundation สำหรับแปลง JSON Data เป็นออบเจกต์ Foundation (NSDictionary, NSArray) และกลับคืน มันทำงานบน iOS, macOS, tvOS และ watchOS โดยไม่ต้องใช้ไลบรารีเพิ่มเติม
Codable เป็นโปรโตคอล Swift สำหรับการเสรียโอาลัย์ซ์แบบกำหนดชนิดอัตโนมัติที่แปลงเป็นโค้ดที่ปลอดภัยด้านชนิด JSONSerialization ทำงานกับชนิด Any แบบไดนามิกและต้องการแปลงชนิดแบบด้วยตน Codable เหมาะสำหรับโปรเจกต์ใหม่ JSONSerialization สำหรับ Objective-C และข้อมูลแบบไดนามิก
ใช้โครงสร้าง do-catch เมื่อเรียก jsonObject ข้อผิดพลาดของ JSONSerialization อยู่ในกลุ่ม CocoaError สำหรับกาารแก้ไขปัญหา ให้ตรวจสอบ NSPropertyListReadCorruptError ซึ่งบ่งบอกรูปแบบข้อมูล JSON ที่ไม่ถูกต้อง
ใช้ JSONSerialization รองรับความลึกของการซ้อนกันของพจนานุกรมและอาร์เรย์ทุกระดับ ออบเจกต์ที่ซ้อนกันทั้งหมดจะถูกแปลงเป็นชนิด Foundation ที่สอดคล้องกัน (NSDictionary, NSArray, NSString, NSNumber) โดยรักษาโครงสร้าง JSON เดิม
JSONSerialization เหมาะสำหรับโครงสร้าง JSON แบบไดนามิก ในโปรเจกต์ Objective-C เมื่อทำงานกับสตรีม และสำหรับการตรวจสอบความถูกต้องของ JSON ผ่าน isValidJSONObject สำหรับโครงสร้างที่กำหนดชนิดและมีโครงสร้างที่รู้จัก Codable เป็นทางเลือกที่ดีกว่า
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม