如何使用 JSON 在 NSDictionary 中序列化自定义对象



我有以下代码:

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

如果对象是NSString的,它将通过,但是一旦我将自定义对象添加到字典中,它就不再有效。我该如何解决这个问题?任何帮助都非常感谢。提前感谢!

简单的事实是:你不能。阅读 NSJSONSerialization 的文档,其中未列出 NSCoding。:(

不能将自定义对象设置为字典的键。确定您的密钥是什么 NSStrings(英语)

文本来自 Foundatoin.framework at func +(BOOL) isValidJSONObject:(id)obj;

- All dictionary keys are NSStrings

原因:这是因为"customObject"不是:NSArray,NSDictionary或NSString。很可能是一个用户定义的类,这是isValidJSONOperation的协定:

/* 如果给定对象可以转换为 JSON 数据,则返回 YES,否则返回 NO。该对象必须具有以下属性:    - 顶级对象是 NSArray 或 NSDictionary    - 所有对象都是 NSString、NSNumber、NSArray、NSDictionary 或 NSNull    - 所有字典键都是 NSStrings    - NSNumbers 不是 NaN 或无穷大 其他规则可能适用。调用此方法或尝试转换是判断给定对象是否可以转换为 JSON 数据的明确方法。 */+ (BOOL)isValidJSONObject:(id)obj;

可能的解决方案 1:将另一个由示例字典调用的 NSDictonary 类型的属性添加到您的自定义对象类中,该字典包含要在 JSON 中添加的属性。

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

可能的解决方案 2:使用要从自定义对象添加到 JSON 中的属性(和值)创建新字典。

键是字符串,但值可以是包括 NSNull 在内的任何对象。

"如何使用 XCode 中的 JSON 序列化 NSDictionary 中的自定义对象?"

归结为我讨厌XCode的另一个原因,并希望有人能把它从1990年代拖出来。

让我们通过一个示例来说明我们应该如何序列化自定义对象。

假设你有一个非常简单的UserRecord类,有一个像这样的.h文件:

@interface UserRecord : NSObject
@property(nonatomic) int UserID;
@property(nonatomic, strong) NSString* FirstName;
@property(nonatomic, strong) NSString* LastName;
@property(nonatomic) int Age;
@end

还有一个像这样的 .m:

@implementation UserRecord
@synthesize UserID;
@synthesize FirstName;
@synthesize LastName;
@synthesize Age;
@end

如果您尝试创建 UserRecord 对象,并使用 NSJSONSerialization 类对其进行序列化。

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];

..它会嘲笑你,抛出异常并使您的应用程序崩溃:

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

解决这场闹剧的一种方法是在NSObject中添加一个函数,将数据转换为NSDictionary,然后将其序列化。

这是我为我的班级准备的新 .m 文件:

@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

实际上,如果您愿意,您可以一次性创建该NSDictionary值:

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

完成此操作后,您可以NSJSONSerialization序列化对象的NSDictionary版本:

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);
}

这将产生我们想要的 JSON 输出:

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

这太令人震惊了。 即使在2015年,Apple的SDK也无法将一组简单的intNSString序列化为JSON。

希望这对其他XCode受害者有所帮助。

您需要

使用 NSCoding 协议来序列化自定义对象。

在 .h 文件中实现 NSCoding 协议,并在自定义类的 .m 文件中实现以下方法。

- (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;
}

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

最新更新