Swift 4中NSMutableArray解归档异常:归档多对象但解档仅返回1个
排查NSMutableArray归档后解归档元素始终为1的问题
嘿,我来帮你拆解这个问题!这种情况我之前也遇到过,大概率是你在存储/解归档的流程里没正确复用已有的数组,导致每次都覆盖了之前的数据,最后看起来只保留了一个元素。咱们一步步来分析:
最可能的原因:每次存储时都新建数组,覆盖旧数据
很多人会犯这个错误——每次添加对象时,直接创建一个新的NSMutableArray,加完对象就归档存储,完全忽略了UserDefaults里已经存过的旧数组。比如错误代码是这样的:
// ❌ 错误写法:每次都新建数组,覆盖之前的所有数据 NSMutableArray *tempArray = [NSMutableArray array]; [tempArray addObject:yourTargetObject]; NSData *archiveData = [NSKeyedArchiver archivedDataWithRootObject:tempArray requiringSecureCoding:YES error:nil]; [[NSUserDefaults standardUserDefaults] setObject:archiveData forKey:@"YourSavedArrayKey"];
这种写法每次都会把旧数组彻底覆盖,自然最后解归档出来永远只有一个元素。
正确的处理流程:先读旧数组,再追加,最后重新归档
你需要先从UserDefaults里取出已归档的数组(如果有的话),在这个数组基础上追加新对象,然后再重新归档存储。代码示例:
// ✅ 正确写法:复用已有数组,追加后再存储 NSString *const kSavedArrayKey = @"YourSavedArrayKey"; // 1. 取出已归档的旧数据 NSData *existingArchiveData = [[NSUserDefaults standardUserDefaults] objectForKey:kSavedArrayKey]; NSMutableArray *savedArray = nil; // 2. 解归档得到数组,没有的话就新建 if (existingArchiveData) { // 注意:如果解归档出来的是不可变NSArray,要转成可变的 NSArray *tempArray = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSArray class] fromData:existingArchiveData error:nil]; savedArray = [NSMutableArray arrayWithArray:tempArray]; } else { savedArray = [NSMutableArray array]; } // 3. 追加新对象 [savedArray addObject:yourTargetObject]; NSLog(@"当前数组元素数量:%lu", (unsigned long)savedArray.count); // 这里可以确认元素已加入 // 4. 重新归档并存储 NSData *newArchiveData = [NSKeyedArchiver archivedDataWithRootObject:savedArray requiringSecureCoding:YES error:nil]; [[NSUserDefaults standardUserDefaults] setObject:newArchiveData forKey:kSavedArrayKey]; [[NSUserDefaults standardUserDefaults] synchronize]; // 可选,但确保立即写入磁盘
其他可能的排查点
如果上面的方法没解决问题,可以检查这几个地方:
- 自定义对象的编码解码是否正确:如果你归档的是自定义对象,必须确保它实现了
NSSecureCoding协议,encodeWithCoder:和initWithCoder:方法要正确处理所有属性,否则可能导致解归档后数据丢失或异常。 - 解归档的类型是否匹配:如果归档的是
NSMutableArray,解归档时尽量指定对应的类名;如果解出来是不可变数组,一定要转成可变数组后再操作。 - 是否有其他代码重置了数组:比如APP启动时、某个回调里有没有重新初始化数组并覆盖存储的情况,这也会导致之前的数据丢失。
可以在关键步骤加日志,比如解归档前后打印数组的count,帮你定位问题:
NSData *existingData = [[NSUserDefaults standardUserDefaults] objectForKey:kSavedArrayKey]; NSLog(@"是否存在已归档数据:%@", existingData ? @"是" : @"否"); if (existingData) { NSArray *temp = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSArray class] fromData:existingData error:nil]; NSLog(@"解归档后的数组元素数量:%lu", (unsigned long)temp.count); }
内容的提问来源于stack exchange,提问作者user1531352
相关产品推荐
相关产品推荐

