在 AFNetworking 的 AFJSONResponseSerializer
中,removesKeysWithNullValues
的功能是通过 AFJSONObjectByRemovingKeysWithNullValues
函数实现的。该函数递归遍历 JSON 对象(NSDictionary
或 NSArray
),移除值为 NSNull
的键,从而清理无效数据。以下是其实现细节:
核心逻辑
-
递归处理数组和字典
- 数组(
NSArray
):遍历每个元素,若元素非NSNull
,则递归处理该元素(可能是嵌套的数组或字典)。 - 字典(
NSDictionary
):遍历所有键值对,若值为nil
或NSNull
,则移除该键;若值为数组或字典,则递归处理。
- 数组(
-
保留可变性
- 根据
readingOptions
中的NSJSONReadingMutableContainers
标志,决定返回可变(NSMutableArray
/NSMutableDictionary
)或不可变容器。
- 根据
-
处理嵌套结构
- 支持多层嵌套的 JSON 结构(如数组中嵌套字典、字典中嵌套数组),确保所有层级的
NSNull
都被移除。
- 支持多层嵌套的 JSON 结构(如数组中嵌套字典、字典中嵌套数组),确保所有层级的
代码实现详解
id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingOptions readingOptions) {
// 处理数组
if ([JSONObject isKindOfClass:[NSArray class]]) {
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)JSONObject count]];
for (id value in (NSArray *)JSONObject) {
if (![value isEqual:[NSNull null]]) { // 过滤 NSNull
[mutableArray addObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions)]; // 递归处理子元素
}
}
return (readingOptions & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray];
}
// 处理字典
else if ([JSONObject isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:JSONObject];
for (id <NSCopying> key in [(NSDictionary *)JSONObject allKeys]) {
id value = (NSDictionary *)JSONObject[key];
if (!value || [value isEqual:[NSNull null]]) {
[mutableDictionary removeObjectForKey:key]; // 移除值为 nil 或 NSNull 的键
} else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
mutableDictionary[key] = AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions); // 递归处理子元素
}
}
return (readingOptions & NSJSONReadingMutableContainers) ? mutableDictionary : [NSDictionary dictionaryWithDictionary:mutableDictionary];
}
// 返回原始值(非容器)
return JSONObject;
}
使用场景
在 AFJSONResponseSerializer
的 responseObjectForResponse:data:error:
方法中,该函数通常在解析 JSON 数据后调用,以清理无效的 null
值。例如:
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error {
id JSON = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:error];
if (self.removesKeysWithNullValues) { // 假设存在此属性
JSON = AFJSONObjectByRemovingKeysWithNullValues(JSON, self.readingOptions);
}
return JSON;
}
关键点
- 目的:避免后续处理中因
NSNull
值导致的崩溃(如[NSNull objectForKey:]
)。 - 兼容性:支持
NSJSONReadingMutableContainers
选项,保持与NSJSONSerialization
的行为一致。 - 性能:递归遍历可能对大型 JSON 数据造成性能开销,但在网络请求中通常可以接受。
示例
假设服务器返回以下 JSON:
{
"name": "John",
"age": null,
"address": {
"city": null,
"zip": "12345"
},
"hobbies": [null, "reading", null]
}
调用 AFJSONObjectByRemovingKeysWithNullValues
后,结果为:
{
"name": "John",
"address": {
"zip": "12345"
},
"hobbies": ["reading"]
}
总结
AFJSONObjectByRemovingKeysWithNullValues
是 AFNetworking 中清理 JSON 数据的关键工具,通过递归遍历和移除 NSNull
值,确保返回的 JSON 对象安全可靠。这一设计在处理不可控的服务器响应时尤为重要。