Swift 4中如何展示JSON的嵌套子数据?
在Swift 4中展示JSON嵌套子数据的实现方案
嘿,看起来你已经搞定了第一层TableView的展示,接下来要处理嵌套的clothe数据对吧?我给你两种常用的实现思路,你可以根据产品需求来选:
方案一:点击Cell跳转到详情TableView展示子数据
这是最常见的做法,用户点击第一层的杂志Cell,进入新页面查看该杂志对应的服饰列表。
步骤说明:
确保数据源就绪:你应该已经有一个存储解析后数据的数组,比如:
var heroStatsArray: [HeroStats] = [] // 解析JSON后填充这个数组的代码你应该已经写好了,这里就不重复啦实现第一个TableView的点击事件:
在didSelectRowAt方法里,获取选中的杂志数据,判断是否有子数据,然后跳转:func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let selectedMagazine = heroStatsArray[indexPath.row] // 先判断是否有服饰数据 guard let clothes = selectedMagazine.clothe, !clothes.isEmpty else { // 没有数据可以提示用户,或者啥也不做 return } // 创建详情页控制器 let detailVC = ClothesTableViewController() detailVC.clothesData = clothes // 导航跳转(如果是导航控制器的话) navigationController?.pushViewController(detailVC, animated: true) // 如果是模态跳转用这个:present(detailVC, animated: true) }实现详情页TableView:
新建一个ClothesTableViewController,定义数据源并实现TableView代理方法:class ClothesTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { var clothesData: [SecondTable] = [] private let tableView = UITableView() override func viewDidLoad() { super.viewDidLoad() title = "服饰列表" // 这里记得给tableView添加约束或者设置frame tableView.dataSource = self tableView.delegate = self tableView.register(UITableViewCell.self, forCellReuseIdentifier: "ClotheCell") } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return clothesData.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ClotheCell", for: indexPath) let clothe = clothesData[indexPath.row] cell.textLabel?.text = clothe.nameClothe // 加载图片:如果是本地图片用UIImage(named:),网络图片可以用Kingfisher这类库 cell.imageView?.image = UIImage(named: clothe.imageClothe) return cell } }
方案二:在同一个TableView中实现折叠/展开效果
如果不想跳转页面,想在同一个TableView里通过展开/折叠来展示子数据,可以用分组TableView的方式实现:
步骤说明:
添加展开状态记录数组:
用来记录每个杂志组是否处于展开状态:var heroStatsArray: [HeroStats] = [] var expandedSections: [Bool] = [] // 每个元素对应一个组的展开状态 // 解析完JSON后初始化这个数组 func setupExpandedStatus() { expandedSections = Array(repeating: false, count: heroStatsArray.count) }修改TableView的分组和行数逻辑:
// 分组数等于杂志的数量 func numberOfSections(in tableView: UITableView) -> Int { return heroStatsArray.count } // 每组的行数:展开状态下显示子数据数量,否则0 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { guard expandedSections[section] else { return 0 } return heroStatsArray[section].clothe?.count ?? 0 } // 自定义Header,用来点击切换展开状态 func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let headerView = UIView() headerView.backgroundColor = .lightGray // 添加标题Label let titleLabel = UILabel(frame: CGRect(x: 16, y: 0, width: view.frame.width - 32, height: 44)) titleLabel.text = heroStatsArray[section].name headerView.addSubview(titleLabel) // 添加点击手势 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(toggleSection(_:))) headerView.addGestureRecognizer(tapGesture) return headerView } // 切换展开状态的方法 @objc func toggleSection(_ gesture: UITapGestureRecognizer) { guard let headerView = gesture.view else { return } let section = tableView.indexPath(for: headerView)?.section ?? 0 expandedSections[section] = !expandedSections[section] // 刷新当前组的行 tableView.reloadSections(IndexSet(integer: section), with: .automatic) }实现Cell的内容展示:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ClotheCell", for: indexPath) let clothe = heroStatsArray[indexPath.section].clothe?[indexPath.row] cell.textLabel?.text = clothe?.nameClothe cell.imageView?.image = clothe.map { UIImage(named: $0.imageClothe) } ?? nil return cell }
注意事项:
- 因为你的
clothe是可选数组,所以所有用到它的地方都要做nil判断,避免崩溃; - 图片加载如果是网络地址,建议用
Kingfisher或者SDWebImage这类第三方库来处理缓存和异步加载; - 记得给TableView注册Cell,或者用xib自定义Cell来优化展示效果。
内容的提问来源于stack exchange,提问作者Gatsby
相关产品推荐
相关产品推荐

