JSONSerialization — μια ενσωματωμένη κλάση iOS από το πλαίσιο Foundation, που προορίζεται για τη μετατροπή JSON σε αντικείμενα Foundation και αντίστροφα. Αυτό το API είναι ο βασικός μηχανισμός εργασίας με JSON σε πλατφόρμες Apple χωρίς σύνδεση βιβλιοθηκών τρίτων, υποστηρίζοντας ανάλυση λεξικών, πινάκων και πρωτόγονων τύπων. Σύμφωνα με το Apple Developer, 2024, το JSONSerialization υποστηρίζει εργασία με Data, ροές και επιλογές ανάγνωσης για ευέλικτη επεξεργασία δεδομένων JSON.
Κύρια σημεία
JSONSerialization — είναι μια κλάση από το πλαίσιο Foundation, διαθέσιμη σε iOS, macOS, tvOS και watchOS. Παρέχει μεθόδους για τη μετατροπή δεδομένων 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 fixtures χωρίς σύνδεση βιβλιοθηκών τρίτων, επιταχύνοντας την ανάπτυξη και τη δημιουργία πρωτοτύπων.
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. Αφού λάβει τα δεδομένα μέσω 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. Οι επιλογές μεταδίδονται μέσω bit mask, επιτρέποντας τον συνδυασμό πολλαπλών τιμών μέσω του τελεστή | για ευέλικτη διαμόρφωση ανάλυσης.
// Διαχείριση διαφορετικών τύπων σφαλμάτων
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 επηρεάζεται από το μέγεθος των δεδομένων και τη συχνότητα κλήσεων. Σε εφάπαξ ανάλυση μιας μικρής απάντησης διακομιστή, η διαφορά δεν είναι αισθητή, αλλά κατά την επεξεργασία δεκάδων megabyte JSON ή συχνών κλήσεων σε βρόχους, πρέπει να ληφθεί υπόψη η επιβάρυνση της μετατροπής τύπων. Το JSONSerialization λειτουργεί σύγχρονα στο τρέχον νήμα, γι' αυτό για μεγάλα έγγραφα συνιστάται η μεταφορά της ανάλυσης σε ουρά παρασκηνίου μέσω του DispatchQueue.global(). Εναλλακτικά, μπορεί να χρησιμοποιηθεί το InputStream για επεξεργασία ροής χωρίς φόρτωση ολόκληρου του αρχείου στη μνήμη, κάτι που είναι κρίσιμο για εφαρμογές με περιορισμένους πόρους. Για εγγραφή JSON σε αρχείο ή ροή δικτύου, η μέθοδος writeJSONObject(_:to:options:error:) επιτρέπει την απευθείας διοχέτευση σειριοποιημένων δεδομένων στο OutputStream χωρίς δημιουργία ενδιάμεσου αντικειμένου Data, μειώνοντας την κατανάλωση μνήμης κατά την εργασία με μεγάλα έγγραφα.
Συχνές ερωτήσεις
JSONSerialization — είναι μια κλάση Foundation για μετατροπή δεδομένων 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 δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης