You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从服务器获取数据并在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

第二步:高效组装树形结构

从服务器拿到原始数组后,我们分两步处理:

  1. 把所有模型存入字典,用locationId作为key,这样找父节点的时候直接通过key取,不用遍历整个数组,效率拉满;
  2. 遍历所有模型,把每个节点挂到对应的父节点下,同时收集根节点(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:38:59