iOS Obj-C:如何从含NSArray的对象生成仅保留指定字段的NSDictionary
你的JSON序列化问题拆解与解决方案
嘿,我来帮你理清这个问题的关键点,以及更高效的实现方式:
首先:NSKeyedArchiver不是生成JSON的最佳选择
你现在用NSKeyedArchiver+NSCoding的方式,本质是做二进制归档,它生成的是苹果专属的序列化数据,不是标准JSON。如果你的目标是生成符合示例的JSON结构,直接用NSJSONSerialization配合自定义对象转字典的方法会更直接、更可控,也避免了POD类型转NSObject后还要再转JSON的冗余步骤。
数组元素外层的包裹是否必要?
这完全取决于你的目标JSON结构需求:
- 如果后端/消费方期望
tasks数组里直接存放任务对象(比如[{"name":"Task1", ...}, {...}]),那外层的{"task": {...}}完全没必要,属于多余嵌套; - 如果消费方明确要求数组每个元素是一个包含
task字段的对象(比如你的示例结构),那这层包裹才是必须的。
简单说:看需求,没有“必须要加”的硬性规则,只看最终JSON的结构约定。
正确实现:自定义对象转字典+JSON序列化
下面是具体的实现思路,能精准控制只保留指定字段,处理POD类型和嵌套数组:
1. 给自定义对象添加转字典的方法
比如你的Task类和SubTask类,分别实现- (NSDictionary *)toDictionary方法,只在方法里暴露需要的字段,同时把POD类型转成NSObject(比如int→NSNumber,bool→NSNumber):
// Task.h @interface Task : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) int repeat; @property (nonatomic, strong) NSArray<SubTask *> *subTasks; - (NSDictionary *)toDictionary; @end // Task.m @implementation Task - (NSDictionary *)toDictionary { // 只保留需要的字段,POD类型转NSNumber NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"name"] = self.name; dict[@"repeat"] = @(self.repeat); // 处理嵌套的子任务数组,递归转字典 NSMutableArray *subTaskDicts = [NSMutableArray array]; for (SubTask *subTask in self.subTasks) { // 如果需要外层包裹sub_task,就把每个子字典包一层: // [subTaskDicts addObject:@{@"sub_task": [subTask toDictionary]}]; // 否则直接添加转好的字典: [subTaskDicts addObject:[subTask toDictionary]]; } dict[@"sub_tasks"] = subTaskDicts; return dict; } @end
// SubTask.h @interface SubTask : NSObject @property (nonatomic, copy) NSString *subName; @property (nonatomic, assign) bool isCompleted; - (NSDictionary *)toDictionary; @end // SubTask.m @implementation SubTask - (NSDictionary *)toDictionary { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"sub_name"] = self.subName; dict[@"is_completed"] = @(self.isCompleted); // bool转NSNumber return dict; } @end
2. 顶层对象转字典并生成JSON
假设你的顶层对象是一个包含title、revision、tasks的模型:
// 构建顶层字典 NSMutableDictionary *topDict = [NSMutableDictionary dictionary]; topDict[@"title"] = @"My Title"; topDict[@"revision"] = @(1); // int转NSNumber // 处理tasks数组 NSMutableArray *taskDicts = [NSMutableArray array]; for (Task *task in yourTaskArray) { // 如果需要外层包裹task,就包一层: // [taskDicts addObject:@{@"task": [task toDictionary]}]; // 否则直接添加转好的字典: [taskDicts addObject:[task toDictionary]]; } topDict[@"tasks"] = taskDicts; // 生成JSON数据 NSError *error = nil; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:topDict options:NSJSONWritingPrettyPrinted error:&error]; if (!error) { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSLog(@"生成的JSON:%@", jsonString); } else { NSLog(@"JSON生成失败:%@", error.localizedDescription); }
如果你坚持用NSKeyedArchiver?
如果因为某些原因必须用NSKeyedArchiver,那你需要先把归档后的NSData转成NSDictionary,再转成JSON,但这个过程会引入很多归档的冗余字段(比如$class信息),你需要额外过滤这些字段,非常麻烦,完全不推荐。
内容的提问来源于stack exchange,提问作者DarkMatter
相关产品推荐
相关产品推荐

