JSONSerialization — یک کلاس داخلی iOS از فریمورک Foundation است که برای تبدیل JSON به اشیاء Foundation و بالعکس طراحی شده است. این API مکانیزم اساسی کار با JSON در پلتفرمهای Apple بدون اتصال کتابخانههای شخص ثالث است و از پارس دیکشنریها، آرایهها و انواع اولیه پشتیبانی میکند. به گزارش Apple Developer, 2024، JSONSerialization از کار با Data، جریانها و گزینههای خواندن برای پردازش انعطافپذیر دادههای JSON پشتیبانی میکند.
نکات اصلی
JSONSerialization — کلاسی از فریمورک Foundation است که در iOS، macOS، tvOS و watchOS در دسترس میباشد. این کلاس متدهایی برای تبدیل Data JSON به اشیاء 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 را بدون اتصال کتابخانههای شخص ثالث فراهم میکنند که توسعه و نمونهسازی اولیه را تسریع میبخشد.
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 نامعتبر — رایجترین علت خرابیها: کاما جا افتاده، کاراکتر اضافی یا نقل قول فرارنشده کل پارس را خراب میکند. نوع دوم خطاها — عدم تطابق با ساختار مورد انتظار: مثلاً سرور به جای دیکشنری یک آرایه بازگرداند. 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:) امکان هدایت مستقیم دادههای سریالشده به OutputStream بدون ایجاد شیء Data میانی را فراهم میکند که مصرف حافظه را هنگام کار با اسناد بزرگ کاهش میدهد.
سوالات متداول
JSONSerialization — کلاس Foundation برای تبدیل Data JSON به اشیاء 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 از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید