Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error with NSJSONSerialization - Invalid type in JSON write (Menu)

I have an App using core data with 3 entities with very similar attributes. The relationship is such as:

Branch ->> Menu ->> Category ->> FoodItem

Each entity has an associated class: example

enter image description here

I am trying to generate JSON representation of the data in sqlite database.

//gets a single menu record which has some categories and each of these have some food items id obj = [NSArray arrayWithObject:[[DataStore singleton] getHomeMenu]];   NSError *err; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:obj options:NSJSONWritingPrettyPrinted error:&err];  NSLog(@"JSON = %@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]); 

But instead of JSON, i get a SIGABRT error.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Menu)' 

Any ideas how to fix it or how to make the entity classes (Branch, Menu etc) JSON serialization compatible?

like image 984
Vaibhav Garg Avatar asked Mar 27 '12 15:03

Vaibhav Garg


People also ask

Why is my menu class not serializable in JSON?

That's because your "Menu" class is not serializable in JSON. Bascially the language doesn't know how your object should be represented in JSON (which fields to include, how to represent references to other objects...)

How to tell if nsjsonserialization is thread safe?

All dictionary keys are instances of NSString. Numbers are neither NaN or infinity. Other rules may apply. Calling isValidJSONObject: or attempting a conversion are the definitive ways to tell if the NSJSONSerialization class can convert given object to JSON data. On iOS 7 and later and macOS 10.9 and later, NSJSONSerialization is thread safe.

How to check if a JSON object can be serialized?

There is a class method isValidJSONObject on NSJSONSerialization that tells you if a object can be serialised. As Julien pointed out you probably have to convert your object to a NSDictionary. NSManagedModel provides some handy methods to get all your attributes for your entity.

Why is my menu class invalid type in JSON write (menu)?

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Menu)' Any ideas how to fix it or how to make the entity classes (Branch, Menu etc) JSON serialization compatible? That's because your "Menu" class is not serializable in JSON.


2 Answers

That's because your "Menu" class is not serializable in JSON. Bascially the language doesn't know how your object should be represented in JSON (which fields to include, how to represent references to other objects...)

From the NSJSONSerialization Class Reference

An object that may be converted to JSON must have the following properties:

  • The top level object is an NSArray or NSDictionary.
  • All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
  • All dictionary keys are instances of NSString.
  • Numbers are not NaN or infinity.

This means that the language knows how to serialize dictionaries. So a simple way to get a JSON representation from your menu is to provide a Dictionary representation of your Menu instances, which you will then serialize into JSON:

- (NSDictionary *)dictionaryFromMenu:(Menu)menu {     [NSDictionary dictionaryWithObjectsAndKeys:[menu.dateUpdated description],@"dateUpdated",     menu.categoryId, @"categoryId",     //... add all the Menu properties you want to include here     nil]; } 

And you could will use it like this :

NSDictionary *menuDictionary = [self dictionaryFromMenu:[[DataStore singleton] getHomeMenu]];   NSError *err; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:menuDictionary options:NSJSONWritingPrettyPrinted error:&err];  NSLog(@"JSON = %@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]); 
like image 92
Julien Avatar answered Oct 05 '22 00:10

Julien


There is a class method isValidJSONObject on NSJSONSerialization that tells you if a object can be serialised. As Julien pointed out you probably have to convert your object to a NSDictionary. NSManagedModel provides some handy methods to get all your attributes for your entity. So you could create a category for NSManagedObject that has a method to convert it over to a NSDictionary. This way you don't have to write a toDictionary method for each entity you want to convert to a dictionary.

@implementation NSManagedObject (JSON)  - (NSDictionary *)toDictionary {     NSArray *attributes = [[self.entity attributesByName] allKeys];     NSDictionary *dict = [self dictionaryWithValuesForKeys:attributes];     return dict; } 
like image 33
Edward Huynh Avatar answered Oct 05 '22 02:10

Edward Huynh