面试官问AFNetworking 是如何处理值为Null的数据的?

22 阅读2分钟

在 AFNetworking 的 AFJSONResponseSerializer 中,removesKeysWithNullValues 的功能是通过 AFJSONObjectByRemovingKeysWithNullValues 函数实现的。该函数递归遍历 JSON 对象(NSDictionaryNSArray),移除值为 NSNull 的键,从而清理无效数据。以下是其实现细节:


核心逻辑

  1. 递归处理数组和字典

    • 数组(NSArray:遍历每个元素,若元素非 NSNull,则递归处理该元素(可能是嵌套的数组或字典)。
    • 字典(NSDictionary:遍历所有键值对,若值为 nilNSNull,则移除该键;若值为数组或字典,则递归处理。
  2. 保留可变性

    • 根据 readingOptions 中的 NSJSONReadingMutableContainers 标志,决定返回可变(NSMutableArray/NSMutableDictionary)或不可变容器。
  3. 处理嵌套结构

    • 支持多层嵌套的 JSON 结构(如数组中嵌套字典、字典中嵌套数组),确保所有层级的 NSNull 都被移除。

代码实现详解

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

使用场景

AFJSONResponseSerializerresponseObjectForResponse: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 对象安全可靠。这一设计在处理不可控的服务器响应时尤为重要。