我有以下代码:
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也无法将一组简单的int
和NSString
序列化为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"];
}