質問

I have the following code:

NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:@"one", @"oneKey", 
@"two", @"twoKey", customObject, @"customObjectKey", nil];
if([NSJSONSerialization isValidJSONObject:dict])
{
    NSLog(@"Went through.");
}

It'll go through if the objects were NSString's, but once I added the customObject into the dictionary, it's no longer valid. How can I fix that? Any help is much appreciated. Thanks in advance!

役に立ちましたか?

解決

You would require to use NSCoding protocol to serialize a custom object.

Implement the NSCoding protocol in .h file and implement the following methods in .m file of your custom class.

- (id)initWithCoder:(NSCoder *)aDecoder
{
   if(self = [super init]) // this needs to be [super initWithCoder:aDecoder] if the superclass implements NSCoding
   {
      aString = [[aDecoder decodeObjectForKey:@"aStringkey"] retain];
      anotherString = [[aDecoder decodeObjectForKey:@"anotherStringkey"] retain];
   }
   return self;
}

and

- (void)encodeWithCoder:(NSCoder *)encoder
{
   // add [super encodeWithCoder:encoder] if the superclass implements NSCoding
   [encoder encodeObject:aString forKey:@"aStringkey"];
   [encoder encodeObject:anotherString forKey:@"anotherStringkey"];
}

他のヒント

The simple truth is: You can't. Read the documentation of NSJSONSerialization, which doesn't list NSCoding. :(

You can't set a custom Object to a key of Dictionary. Get sure, what your keys is NSStrings

Text from Foundatoin.framework at func +(BOOL) isValidJSONObject:(id)obj;

- All dictionary keys are NSStrings

CAUSE:This is because "customObject" is not: NSArray, NSDictionary nor NSString. Most probably will be a user defined class, this is the contract for isValidJSONOperation:

/* Returns YES if the given object can be converted to JSON data, NO otherwise. The object must have the following properties:
    - Top level object is an NSArray or NSDictionary
    - All objects are NSString, NSNumber, NSArray, NSDictionary, or NSNull
    - All dictionary keys are NSStrings
    - NSNumbers are not NaN or infinity
 Other rules may apply. Calling this method or attempting a conversion are the definitive ways to tell if a given object can be converted to JSON data.
 */
+ (BOOL)isValidJSONObject:(id)obj;

POSSIBLE SOLUTION 1:Add into your customObject class another attribute of type NSDictonary called by example dictionary which hold the attributes to add in the JSON.

NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:@"one", @"oneKey", 
@"two", @"twoKey", customObject.dictionary, @"customObjectKey", nil];

POSSIBLE SOLUTION 2: Create a new dictionary with the attributes (and values) that you want to add in the JSON from customObject.

Keys are strings, but the values can be any object including NSNull.

"How to serialize a custom object in NSDictionary using JSON in XCode?"

Chalk up another reason why I loathe XCode, and wish someone would drag it from the 1990s.

Let's go through an example of how we're expected to serialize a custom object.

Supposing you had a very simple UserRecord class, with a .h file like this:

@interface UserRecord : NSObject

@property(nonatomic) int UserID;
@property(nonatomic, strong) NSString* FirstName;
@property(nonatomic, strong) NSString* LastName;
@property(nonatomic) int Age;

@end

And an .m like this:

@implementation UserRecord

@synthesize UserID;
@synthesize FirstName;
@synthesize LastName;
@synthesize Age;

@end

If you tried to create a UserRecord object, and serialize it using the NSJSONSerialization class..

UserRecord* sampleRecord = [[UserRecord alloc] init];
sampleRecord.UserID = 13;
sampleRecord.FirstName = @"Mike";
sampleRecord.LastName = @"Gledhill";
sampleRecord.Age = 82;

NSError* error = nil;
NSData* jsonData2 = [NSJSONSerialization dataWithJSONObject:sampleRecord options:NSJSONWritingPrettyPrinted error:&error];

..it'd laugh at you, throw an exception and crash your application:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[NSJSONSerialization dataWithJSONObject:options:error:]: Invalid top-level type in JSON write'

One way to get around this farce is to add a function to your NSObject to convert your data into an NSDictionary, and then serialize that.

Here's my new .m file for my class:

@implementation UserRecord

@synthesize UserID;
@synthesize FirstName;
@synthesize LastName;
@synthesize Age;

-(NSDictionary*)fetchInDictionaryForm
{
    NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];

    [dict setObject:[NSNumber numberWithInt:UserID] forKey:@"UserID"];
    [dict setObject:FirstName forKey:@"FirstName"];
    [dict setObject:LastName forKey:@"LastName"];
    [dict setObject:[NSNumber numberWithInt:Age] forKey:@"Age"];

    return dict;
}

@end

Actually, you could create that NSDictionary value in one go, if you wanted to:

-(NSDictionary*)fetchInDictionaryForm
{
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                         [NSNumber numberWithInt:UserID], @"UserID",
                         FirstName, @"FirstName",
                         LastName,@"LastName",
                         [NSNumber numberWithInt:Age], @"Age",
                         nil];
    return dict;
}

Once you've done this, you can get NSJSONSerialization to serialize the NSDictionary version of your object:

UserRecord* sampleRecord = [[UserRecord alloc] init];
sampleRecord.UserID = 13;
sampleRecord.FirstName = @"Mike";
sampleRecord.LastName = @"Gledhill";
sampleRecord.Age = 82;


NSDictionary* dictionary = [sampleRecord fetchInDictionaryForm];
if ([NSJSONSerialization isValidJSONObject:dictionary])
{
    NSError* error = nil;
    NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:&error];
    NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

    NSLog(@"%@", jsonString);
}

And this will produce the JSON output we wanted:

{
  "UserID" : 13,
  "FirstName" : "Mike",
  "LastName" : "Gledhill",
  "Age" : 82
}

It's shocking. Even in 2015, Apple's SDK isn't capable of serializing a simple set of ints and NSStrings into JSON.

Hope this helps other XCode victims.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top