TypedJSON
处理 Objective-C JSON 字典的方式很丑。
Objective-C 是一种运行时,弱类型语言。Objective-C 中的 NSDictionary
类不是一个类型安全的对象。
假设我们有一个 json 字典
NSDictionary *json = @{ @"username": @"tp", @"password": @"123456", @"scores": @{ @"programming": @70, @"language": @80 }, @"tels": @[ @"1367890876", @"02884435261" ] };
我们可以这样访问字典:
NSString *username = json[@"username"];
if (!username || ![username isKindOfClass:NSString.class] || username.length == 0) {
return;
}
// Do something with username string
或者:
NSDictionary *scores = json[@"scores"];
if (!scores || ![scores isKindOfClass:NSDictionary.class] || scores.count == 0) {
return;
}
NSNumber *score = scores[@"programming"];
if (!score || ![score isKindOfClass:NSNumber.class]) {
return;
}
// Do something with programming score number
这里的问题在于,我们做了很多类型与值的检查以确保类型安全性,这使得我们的代码很丑。
这种方法更好
使用 TypedJSON
,我们使用链式操作符以语义化的方式解决这个问题。这试图确保代码的优雅性和可读性。
NSString *username = json.tj.string(@"username").without.empty.value;
if (!username) {
return;
}
// Do something with username string
和
NSNumber *score = json.tj.dictionary(@"scores").number(@"programming").value;
if (!score) {
return;
}
// Do something with programming score number
更多示例
此示例中的 json 数据
{
"username": "tp",
"password": "123456",
"scores": {
"programming": 70,
"language": 80
},
"tels": [
"+8613612345678",
"028-84555555"
]
}
如何使用 TypedJSON
访问此 json 字典
NSDictionary *json = [self loadJSON];
// Get username from json exclued empty string value '', return 'anonymous' while nil.
NSString *username = json.tj.string(@"username").without.empty.defaults(@"anonymous").value;
// Get programming score number in scores dictionary from json.
NSNumber *programmingScore = json.tj.dictionary(@"scores").number(@"programming").value;
// Get politics score number in scores dictionary from json, return 0 while politics do not exists.
NSNumber *politicsScore = json.tj.dictionary(@"scores").number(@"politics").with.defaults(@0).value;
NSLog(@"The programming score of %@ is %@, and politics %@.", username, programmingScore, politicsScore);
安装
TypedJSON
可以通过CocoaPods进行安装。要安装它,只需将以下行添加到您的Podfile
pod 'TypedJSON'
然后运行pod install
以进行集成。
用法
要导入TypedJSON
,您只需
#import <TypedJSON/TypedJSON.h>
在字典中以类型安全的方式读取值
使用指定键在字典中读取字符串
json.tj.string(@"foo").value;
如果值不是
NSString
类型,则值可能是nil
。
使用指定键在字典中读取数字
json.tj.number(@"foo").value;
如果值不是
NSNumber
类型,则值可能是nil
。
使用指定键在字典中读取数组
json.tj.array(@"foo").value;
如果值不是
NSArray
类型,则值可能是nil
。
使用指定键在字典中读取字典
json.tj.dictionary(@"foo").value;
如果值不是
NSDictionary
类型,则值可能是nil
。
确保不为空
有时我们在字典中会得到空值,例如
- 空字符串:
""
- 空数组:
@[]
- 空字典:
@{}
使用- empty
操作符来忽略它们
json.tj.string(@"foo").without.empty.value;
如果"foo"的值为一个空字符串
""
,则返回nil
json.tj.array(@"foo").without.empty.value;
如果"foo"的值为一个空数组
@[]
,则返回nil
json.tj.dictionary(@"foo").without.empty.value;
如果"foo"的值为一个空字典
@{}
,则返回nil
nil
值时提供默认值
在获取假设我们得到了链中的nil
值,我们需要提供一个默认值
json.tj.string(@"foo").with.defaults(@"bar").value;
可以省略
- with
操作符,这只是为了确保语句的语义。
《- any》运算符
此运算符仅通过指定键获取值,不进行类型检查。
json.tj.any(@"foo").value;
返回值是
id
类型。
或者,您可以使用 Valuable
扩展来执行类型检查。
json.tj.any(@"foo").stringValue;
- stringValue
确保返回值匹配NSString
类型,如果不匹配则返回nil
。
以链式方式访问值
假设值被包装在内层字典中。
{
"foo": {
"bar": {
"greeting": "Hello ~"
}
}
}
我们可以以链式方式访问 greeting
。
json.tj.dictionary(@"foo").dictionary(@"bar").string(@"greeting").value;
《- find》运算符
在上面的示例中,我们通过运算符链访问 greeting
,使用 - find
运算符可以修改代码。
json.tj.find(@"greeting").value;
- find
运算符递归枚举字典以获取匹配特定键的值,但不执行类型检查。为了确保类型安全,我们可以使用 Valuable
扩展方法 - stringValue
。
json.tj.find(@"greeting").stringValue;
《- as》运算符
此运算符类似于 Valuable
扩展方法。它确保值匹配指定的类类型。通常我们在运算符链中使用此运算符在 - find
或 - any
运算符之后。
json.tj.find(@"greeting").as(NSString.class).value;
确保
- find
运算符的@"greeting"
结果值匹配NSString
类。
等同于
json.tj.find(@"greeting").stringValue;
错误情况
如果 json
对象为 nil
或不是 NSDictionary
的子类,直接使用 .tj
可能会导致程序崩溃。因此,我们在使用 tj 访问之前,应该对 json
对象进行 可空性 & 类型检查。或者,我们可以使用 TJ(json)
宏来为您执行此操作。
// The `json` object could be `nil`, or it's class is NOT a kind of NSDicionary.
NSString *username = TJ(json).string(@"username").without.empty.defaults(@"anonymous").value;
作者
许可证
TypedJSON 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。