如何在iOS Swift中基于NSObject实现合规JSON解析安全类并防崩溃?
安全处理iOS JSON解析:基于NSObject的兼容模型类实现
在iOS开发里,JSON解析时模型类和JSON键编码规则不兼容绝对是坑人的常见崩溃原因——尤其是后端返回的JSON突然多了个键、少了个键,或者键的命名规则和你模型的属性不一样的时候。今天我就给你整个基于NSObject的安全模型类方案,不仅能避免运行时崩溃,还能在控制台打印出那些不兼容的键,帮你快速定位问题。
核心实现思路
- 重写
setValue:forKey:和setValue:forUndefinedKey:方法,拦截系统的键值赋值流程 - 检查模型类是否存在对应属性,不存在就跳过赋值,不抛出异常
- 自动处理下划线命名(比如
user_name)到驼峰式属性(userName)的映射 - 实时打印缺失或不匹配的键信息,方便调试
完整代码实现
@interface SafeJSONModel : NSObject @end @implementation SafeJSONModel - (void)setValue:(id)value forKey:(NSString *)key { // 先检查当前类是否有对应的属性 BOOL hasMatchingProperty = NO; unsigned int propertyCount; objc_property_t *properties = class_copyPropertyList([self class], &propertyCount); for (unsigned int i = 0; i < propertyCount; i++) { objc_property_t property = properties[i]; NSString *propName = [NSString stringWithUTF8String:property_getName(property)]; if ([propName isEqualToString:key]) { hasMatchingProperty = YES; break; } } free(properties); if (hasMatchingProperty) { // 属性存在,正常调用父类方法赋值 [super setValue:value forKey:key]; } else { // 属性不存在,打印警告日志 NSLog(@"⚠️ 警告:模型类 %@ 中不存在与JSON键 '%@' 对应的属性,已跳过赋值", NSStringFromClass([self class]), key); } } // 处理JSON下划线键到模型驼峰属性的映射逻辑 - (NSString *)camelCaseKeyFromJSONKey:(NSString *)jsonKey { NSMutableString *camelCaseKey = [NSMutableString string]; BOOL needUppercaseNextChar = NO; for (NSInteger i = 0; i < jsonKey.length; i++) { unichar currentChar = [jsonKey characterAtIndex:i]; if (currentChar == '_') { needUppercaseNextChar = YES; } else { if (needUppercaseNextChar) { [camelCaseKey appendString:[[NSString stringWithCharacters:¤tChar length:1] uppercaseString]]; needUppercaseNextChar = NO; } else { [camelCaseKey appendString:[NSString stringWithCharacters:¤tChar length:1]]; } } } return camelCaseKey; } // 拦截系统的undefinedKey异常,尝试驼峰匹配后仍失败则打印错误 - (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSString *camelCaseKey = [self camelCaseKeyFromJSONKey:key]; unsigned int propertyCount; objc_property_t *properties = class_copyPropertyList([self class], &propertyCount); BOOL foundCamelCaseProperty = NO; for (unsigned int i = 0; i < propertyCount; i++) { objc_property_t property = properties[i]; NSString *propName = [NSString stringWithUTF8String:property_getName(property)]; if ([propName isEqualToString:camelCaseKey]) { foundCamelCaseProperty = YES; [super setValue:value forKey:camelCaseKey]; break; } } free(properties); if (!foundCamelCaseProperty) { NSLog(@"❌ 错误:模型类 %@ 中既不存在JSON键 '%@',也不存在对应的驼峰式属性 '%@',已跳过赋值", NSStringFromClass([self class]), key, camelCaseKey); } } @end
使用示例
比如你需要一个用户模型,直接继承SafeJSONModel即可:
@interface UserModel : SafeJSONModel @property (nonatomic, copy) NSString *userName; @property (nonatomic, assign) NSInteger age; @end @implementation UserModel @end
假设后端返回这样的JSON:
{ "user_name": "John Doe", "age": 28, "email": "john@example.com" }
解析时控制台会输出:
⚠️ 警告:模型类 UserModel 中不存在与JSON键 'email' 对应的属性,已跳过赋值
而user_name会自动映射到userName属性,整个过程不会崩溃。
扩展优化建议
- 如果你的项目用的是其他键编码规则(比如首字母大写的键),可以修改
camelCaseKeyFromJSONKey:方法的逻辑来适配 - 可以把日志输出换成自定义的日志框架,或者把这些不兼容的键信息上报到错误监控系统,方便排查线上问题
- 如果需要处理复杂类型转换(比如JSON字符串转
NSDate),可以在setValue:forKey:中添加对应的类型判断和转换逻辑
内容的提问来源于stack exchange,提问作者iAj
相关产品推荐
相关产品推荐

