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

如何提取Hierarchies嵌套结构全层级数据实现UITableView手风琴效果

解决方案

1. 修复模型定义错误

你的AssignedHierarchyLevelModel重复定义了两次Hierarchies结构体,首先删除多余的第二个Hierarchies定义即可,保留的递归结构体本身已经支持任意层级的树形结构,修复后的模型如下:

struct AssignedHierarchyLevelModel {
    let result: [Result]?

    init(_ json: JSON) {
        result = json["result"].arrayValue.map { Result($0) }
    }

    struct Result {
        let name: String?
        let hierarchies: [Hierarchies]?

        init(_ json: JSON) {
            name = json["name"].stringValue
            hierarchies = json["hierarchies"].arrayValue.map { Hierarchies($0) }
        }
    }

    struct Hierarchies {
        // 新增唯一ID,用于后续手风琴展开状态标识
        let id = UUID()
        let hierarchyOrder: Int?
        let hierarchyLevel: Int?
        let name: String?
        let hierarchies: [Hierarchies]?
        let isEnabled: Bool?

        init(_ json: JSON) {
            hierarchyOrder = json["hierarchy_order"].intValue
            hierarchyLevel = json["hierarchy_level"].intValue
            name = json["name"].stringValue
            hierarchies = json["hierarchies"].arrayValue.map { Hierarchies($0) }
            isEnabled = json["is_enabled"].boolValue
        }
    }
}

2. 实现递归提取全层级节点方法

你之前的numberOfChild方法是硬编码仅处理2级层级,所以无法获取深层数据,替换为递归遍历逻辑即可支持无限层级提取,扩展Hierarchies结构体添加递归方法:

extension AssignedHierarchyLevelModel.Result.Hierarchies {
    /// 递归获取当前节点的所有层级后代节点,参数控制是否包含节点自身
    func allDescendants(includeSelf: Bool = true) -> [AssignedHierarchyLevelModel.Result.Hierarchies] {
        var result = includeSelf ? [self] : []
        hierarchies?.forEach { child in
            result.append(contentsOf: child.allDescendants())
        }
        return result
    }
}

如果要提取某个Result下的所有层级节点,直接调用即可:

let allNodes = result.hierarchies?.flatMap { $0.allDescendants() } ?? []

3. 业务场景适配

场景1:直接展示所有层级节点(无折叠)

数据绑定时直接拉平所有节点作为数据源即可:

// 存储拉平后的全量节点
var allFlattenNodes: [AssignedHierarchyLevelModel.Result.Hierarchies] = []

func dataBindAccountSettingHierarchyLevel(){
    allFlattenNodes.removeAll()
    self.assignedhierarchyResult = self.assignedHierarchyLevelModel?.result ?? []
    // 递归拉平所有层级节点
    assignedhierarchyResult.forEach { result in
        allFlattenNodes.append(contentsOf: result.hierarchies?.flatMap { $0.allDescendants() } ?? [])
    }
    tableView.reloadData()
}

// TableView数据源直接返回数组长度
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return allFlattenNodes.count
}

渲染行时根据hierarchyLevel设置左侧缩进即可体现层级关系。

场景2:实现手风琴折叠效果

新增展开状态存储,动态计算当前需要展示的行数:

// 存储当前展开的节点ID
var expandedNodeIds = Set<UUID>()

// 计算对应Section下需要展示的行数
func getRowCountForSection(_ section: Int) -> Int {
    guard let topHierarchies = assignedhierarchyResult[section].hierarchies else { return 0 }
    var count = 0
    func countExpandedNodes(nodes: [AssignedHierarchyLevelModel.Result.Hierarchies]) {
        nodes.forEach { node in
            count += 1
            // 节点已展开则继续统计子节点
            if expandedNodeIds.contains(node.id), let children = node.hierarchies, !children.isEmpty {
                countExpandedNodes(nodes: children)
            }
        }
    }
    countExpandedNodes(nodes: topHierarchies)
    return count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return getRowCountForSection(section)
}

// 点击节点时切换展开状态
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // 此处省略获取当前点击节点的逻辑
    let currentNode = getNodeForIndexPath(indexPath)
    guard !currentNode.hierarchies.isEmpty else { return }
    if expandedNodeIds.contains(currentNode.id) {
        expandedNodeIds.remove(currentNode.id)
    } else {
        expandedNodeIds.insert(currentNode.id)
    }
    // 局部刷新对应区域
    tableView.reloadSections(IndexSet(integer: indexPath.section), with: .automatic)
}

内容的提问来源于stack exchange,提问作者kiran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 11:36:07