如何从服务器获取数据并在iOS中用RATreeView构建树形视图
搞定iOS RATreeView的树形数据组装方案
嘿,我来帮你搞定这个RATreeView的树形数据组装问题!其实核心思路就是先建立数据的快速映射,再批量关联父子节点,比你之前想的存parentId数组要高效得多,而且逻辑清晰。
第一步:先定义数据模型
首先把服务器返回的字段转成OC模型,记得给子节点留个存储数组,另外注意id是OC的关键字,最好改个名字比如locationId避免冲突:
@interface LocationModel : NSObject @property (nonatomic, copy) NSString *objectId; @property (nonatomic, copy) NSString *parentId; @property (nonatomic, copy) NSString *locationId; // 替换原有的id,避免关键字冲突 @property (nonatomic, copy) NSString *locationName; @property (nonatomic, strong) NSMutableArray<LocationModel *> *children; // 存储子节点 @end @implementation LocationModel // 可以在这里写字典转模型的方法,或者用MJExtension之类的库快速转换 @end
第二步:高效组装树形结构
从服务器拿到原始数组后,我们分两步处理:
- 把所有模型存入字典,用
locationId作为key,这样找父节点的时候直接通过key取,不用遍历整个数组,效率拉满; - 遍历所有模型,把每个节点挂到对应的父节点下,同时收集根节点(parentId为空/0/特定标识的节点)。
代码示例:
// 假设你从服务器请求到的原始数据是NSArray<NSDictionary *> *rawLocationData NSMutableDictionary *locationMap = [NSMutableDictionary dictionary]; NSMutableArray *rootNodes = [NSMutableArray array]; // 第一步:将所有数据转成模型并存入字典 for (NSDictionary *dict in rawLocationData) { LocationModel *model = [[LocationModel alloc] init]; model.objectId = dict[@"objectId"]; model.parentId = dict[@"parentId"]; model.locationId = dict[@"id"]; // 对应服务器返回的id字段 model.locationName = dict[@"locationName"]; model.children = [NSMutableArray array]; // 初始化子节点数组 [locationMap setObject:model forKey:model.locationId]; } // 第二步:关联父子节点,收集根节点 for (LocationModel *model in locationMap.allValues) { // 判断根节点的条件,根据你的服务器返回调整:比如parentId为空、0或者空字符串 if (!model.parentId || [model.parentId isEqualToString:@"0"] || model.parentId.length == 0) { [rootNodes addObject:model]; } else { // 通过字典快速找到父节点 LocationModel *parentModel = locationMap[model.parentId]; if (parentModel) { [parentModel.children addObject:model]; } else { // 容错处理:如果父节点不存在,直接作为根节点(避免数据丢失) NSLog(@"Warning: Parent node not found for id %@", model.locationId); [rootNodes addObject:model]; } } } // 现在rootNodes就是所有根节点,每个节点的children里已经存好了对应的子节点
第三步:适配RATreeView数据源
有了组装好的树形数据,直接实现RATreeView的数据源方法就行:
#pragma mark - RATreeViewDataSource - (NSInteger)treeView:(RATreeView *)treeView numberOfChildrenOfItem:(id)item { if (!item) { // 没有item时,返回根节点的数量 return rootNodes.count; } else if ([item isKindOfClass:[LocationModel class]]) { LocationModel *model = (LocationModel *)item; return model.children.count; } return 0; } - (id)treeView:(RATreeView *)treeView child:(NSInteger)index ofItem:(id)item { if (!item) { return rootNodes[index]; } else if ([item isKindOfClass:[LocationModel class]]) { LocationModel *model = (LocationModel *)item; return model.children[index]; } return nil; } // 自定义cell显示 - (UITableViewCell *)treeView:(RATreeView *)treeView cellForItem:(id)item { static NSString *cellID = @"LocationTreeCell"; UITableViewCell *cell = [treeView dequeueReusableCellWithIdentifier:cellID]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; } LocationModel *model = (LocationModel *)item; cell.textLabel.text = model.locationName; // 可以根据层级设置缩进,或者自定义样式 return cell; }
几个注意点
- 根节点判断:一定要根据你服务器的实际返回调整,比如有的服务器根节点的parentId是
null,有的是"0",别硬套代码; - 容错处理:如果遇到某个节点的parentId不存在(比如数据错误),记得做兜底,不然这个节点会丢失;
- 性能优化:用字典映射的方式时间复杂度是O(n),比嵌套遍历的O(n²)高效太多,数据量大的时候差异很明显。
内容的提问来源于stack exchange,提问作者Owen.Wang
相关产品推荐
相关产品推荐

