Objective-C 中本地集合与 JSON 之间的转换。
静态方法在发生错误时(如 JSON 无法传递、为 nil 或无效的预期类型)总是返回 nil
。
您可以使用 JSONString
或 JSONData
分别获取 JSON 编码的 NSString 或 NSData 版本。
NSDictionary *d = @{@"foo": @"bar"};
// {"foo":"bar"}
NSString *JSONString = [d JSONString];
// The same value as above but as a NSData
NSData *JSONData = [d JSONData];
这两种方法都适用于 NSNull
、NSNumber
、NSArray
、NSDictionary
、NSObject
和 NSString
。
您也可以转换任何 NSObject
的子类
@interface SomeObject : NSObject
@property NSString *string;
@property int number;
@end
SomeObject *myObject = [SomeObject new];
myObject.string = @"foo";
myObject.number = 123;
// {"string":"foo","number":123}
NSString *json = [myObject JSONString];
如果您需要控制自定义对象的序列化方式,可以重写 [JSONDictionary]
方法
@implementation SomeObject
- (NSDictionary *)JSONDictionary
{
return @{
@"number": self.number,
@"secret": @"bar",
};
}
@end
SomeObject *myObject = [SomeObject new];
myObject.string = @"foo";
myObject.number = 123;
// {"number":123,"secret":"bar"}
NSString *json = [myObject JSONString];
将 JSON 转换为对象的最简单方法是将其通过 NSObject 运行
NSString *json = @"{\"foo\":\"bar\"}";
id object = [NSObject objectWithJSONString:json];
但是,如果您知道传入值的类型,应使用相应的类工厂(而不是盲目地转换)
NSString *json = @"{\"foo\":\"bar\"}";
NSDictionary *d = [NSDictionary dictionaryWithJSONString:json];
当使用特定类时,它不会接受有效 JSON 值的意外类型,以防止出现错误,例如
NSString *json = @"{\"foo\":\"bar\"}";
// `a` is `nil` because we only intend to decode a JSON array.
NSArray *a = [NSArray arrayWithJSONString:json];
// `b` is an instance of `NSDictionary` but future code will be treating it like
// an `NSArray` which will surely cause very bad things to happen...
NSArray *b = [NSObject objectWithJSONString:json];
假设您有这个
@interface SomeObject : NSObject
@property NSString *string;
@property int number;
@end
与解包原生类型的相同方法,只不过因为静态方法 [objectWithJSONString:]
是针对 SomeObject
调用的,所以您正在表示必须反序列化为此类型的对象。
NSString *json = @"{\"string\":\"foo\",\"number\":123};
SomeObject *myObject = [SomeObject objectWithJSONString:json];
// 123
myObject.number;
// Do NOT do this. Otherwise you will get an NSDictionary.
// SomeObject *myObject = [NSObject objectWithJSONString:json];
对象递归构造,首先检查属性是否存在,如果存在且数据不以 NS
前缀,则将创建另一个自定义对象并继续。这意味着可以像使用任何具体代码一样使用 JSON 来解包简单对象,但这也有些限制
这是一个危险的操作。并非所有属性都是公开的,甚至可能不存在,所以很容易缺失类型,在使用解包后的对象时可能导致严重的内存错误。
它始终使用 [init]
构造函数,这可能是错误的,甚至可能不可用,使得对象构造变得不可能。
解包对象的一个更安全的做法是重写 [setValue:forProperty:]
方法。这允许您准确控制每个属性的所需逻辑。
注意:这是一个对 [setValue:forKey:]
的包装,如果未重写它,则会调用 [setValue:forKey:]
。
@implementation SomeObject
- (void)setValue:(id)value forProperty:(NSString *)key
{
// Only allow these two properties to be set.
NSArray *properties = @[@"number", @"string"];
if ([properties indexOfObject:key] != NSNotFound) {
[self setValue:value forKey:key];
}
}
@end
默认情况下,序列化的JSON不会包含额外空格,这对传输和存储最佳,但对调试来说可读性较差。您可以通过指定缩进大小生成具有美化的JSON。
NSDictionary *object = @{@"abc": @"def"};
// {
// "abc": "def"
// }
NSString *result = [object prettyJSONStringWithIndentSize:2];
对于每个工厂方法都有一个可变对应物,用于生成可以在解包后安全的直接编辑的对象。
NSString *json = @"{\"foo\":\"bar\"}";
NSDictionary *d = [NSDictionary dictionaryWithJSONString:json];
NSMutableDictionary *md = [NSMutableDictionary mutableDictionaryWithJSONString:json];
每个工厂方法都有一个直接从文件生成对象的方式。
NSArray *foo = [NSArray arrayWithJSONFile:@"foo.json"];
如果文件不存在、解析出错或JSON类型错误,则返回 nil
。
此外,您还可以从文件创建可变对象。
NSMutableArray *foo = [NSMutableArray mutableArrayWithJSONFile:@"foo.json"];
在大多数情况下,您不会遇到问题。然而,默认行为是返回 nil
并隐藏错误原因。如果您想要更安全地处理错误,可以提供一个指向 NSError
的引用。
NSError *error;
NSString *result = [object JSONStringOrError:&error];
if (error) {
// Use these:
// error.localizedDescription
// error.localizedFailureReason
}
这对于 JSONDataOrError:
和 JSONDictionaryOrError:
都是一样的。