【问题标题】:Swift: How to configure a tableview with multiple sections dynamically using JSON dataSwift:如何使用 JSON 数据动态配置具有多个部分的 tableview
【发布时间】:2019-02-06 07:25:19
【问题描述】:

我正在尝试使用从服务器上的端点检索到的 JSON 数据来填充具有多个部分的动态 UITableView。

tableview 应该显示用户项目的列表,按团队组织,顶部有来自任何团队的最多 5 个最近项目。

但是,由于返回的 JSON 很复杂,我在用他们的项目填充团队(部分)时遇到了问题。我知道我必须将项目的团队 ID 与团队的团队 ID 进行比较,以确定该项目是否属于该团队。但我被困在下一步:如何存储属于一个团队的所有项目,然后索引此数据结构以显示部分标题的团队名称,然后显示该给定团队的项目。

到目前为止我尝试过的事情:

  1. 循环遍历从端点获取的每个项目。
  2. 检查当前项目的团队 ID 是否与当前团队的团队 ID 匹配。
  3. 如果匹配,则将该项目添加到该团队

    // Loop through each project
    for project in projects {
        // If the current project belongs to the current team
        if project.relationships.team.id == teams[section - 1].id {
            // Add the project to that team
    
        }
    
    }
    

最近的部分(顶部的第一部分)保留用于包含标题(项目名称)和副标题(包含项目的团队)的表格视图单元列表。

每个团队的表格视图必须有 1 个部分,每个部分都显示团队的项目。表格视图单元格应包含显示项目名称的标题。

以下是端点的 JSON 响应示例。

我遇到的问题是弄清楚如何将每个项目分配给其关联的团队,然后索引该数据结构(我在想一个包含团队数组的二维数组,每个团队都持有与其关联的项目数组)。

included 是一个团队数组。 data 是一个项目数组。

{
  "included": [
    {
      "type": "teams",
      "id": "1",
      "attributes": {
        "name": "Team1"
      }
    },
    {
      "type": "teams",
      "id": "2",
      "attributes": {
        "name": "Team2"
      }
    },
    {
      "type": "teams",
      "id": "3",
      "attributes": {
        "name": "Team3"
      }
    }
  ],
  "data": [
    {
      "type": "projects",
      "id": "1",
      "relationships": {
        "team": {
          "id": "1",
          "type": "teams"
        }
      },
      "attributes": {
        "name": "House of Cards",
      }
    },
    {
      "type": "projects",
      "id": "2",
      "relationships": {
        "team": {
          "id": "1",
          "type": "teams"
        }
      },
      "attributes": {
        "name": "Arrested Development",
      }
    },
    {
      "type": "projects",
      "id": "3",
      "relationships": {
        "team": {
          "id": "1",
          "type": "teams"
        }
      },
      "attributes": {
        "name": "Orange Is The New Black",
      }
    },
    ...
  ]
}

我基于 JSON 创建了一个模型(及其关联的模型):

struct JSON: Codable {
    let included: [Included]
    let data: [Datum]
}

这是我的代码的相关sn-ps:

// This should belong in the fetchData() function to be called in viewDidLoad but I believe I need access to the `section`

    var arrProjects = [Datum]()
    // Loop through each project
    for project in projects {
        // If the current project belongs to the current team
        if project.relationships.team.id == teams[section - 1].id {
            // Add the project to that team
            arrProjects.append(project)

//                let teamName = teams[section - 1].attributes.name
//                projectsByTeam.append([teamName: arrProjects])
            //projectsByTeam[section-1] = [teamName: arrProjects]

            let teamName = teams[section - 1].attributes.name
            let team = [teamName: arrProjects]
            projectsByTeam.append(team)
        }

    }


let decoder = JSONDecoder()
self?.json = try decoder.decode(JSON.self, from: data)

guard let json = self?.json else { return }

self?.teams = json.included
self?.projects = json.data

DispatchQueue.main.async { [weak self] in
    self?.tableView.reloadData()
}

...

func numberOfSections(in tableView: UITableView) -> Int {

    if let numberOfTeams = teams?.count {
        return 1 + numberOfTeams
    }

    return 1

}

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

    guard let projects = projects else { return 0 }
    guard let teams = teams else { return 0 }

    let numberOfProjects = projects.count

    if section == 0 {
        // Recent section
        if numberOfProjects <= 5 {
            return 0
        } else if numberOfProjects > 5 && numberOfProjects < 10 {
            return numberOfProjects - 5
        } else if numberOfProjects >= 10 {
            return 5
        }
    }

    // *NEED TO FIND THE NUMBER OF PROJECTS FOR EACH REMAINING SECTION (WHICH IS A TEAM)*
    // How to index the data structure that holds the projects for each team?

    return 0

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    guard let project = projects?[indexPath.row] else { return UITableViewCell() }

    if indexPath.section == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: Constants.RecentCellReuseIdentifier, for: indexPath) as! RecentTableViewCell
        cell.textLabel?.text = project.attributes.name
        cell.detailTextLabel?.text = project.relationships.team.id

        return cell
    }

    let cell = tableView.dequeueReusableCell(withIdentifier: Constants.ProjectCellReuseIdentifier, for: indexPath) as! ProjectTableViewCell
    // How to index the data structure that holds the projects for each team?
    //cell.textLabel?.text = projectsByTeam?[indexPath.section][indexPath.row]

    return cell
}

tableview 的结构大致如下所示:

第 0 部分 - 最近

  • ProjectA(团队 1)
  • ProjectD(第 2 组)
  • ProjectE(第 3 组)

第 1 部分 - 团队 1

  • 项目A
  • 项目B

第 2 部分 - 第 2 组

  • 项目C
  • 项目D

第 3 部分 - 第 3 组

  • 项目E
  • 项目F

【问题讨论】:

    标签: json swift uitableview model


    【解决方案1】:

    你可以像这样构建你的数据结构:

    var teams = [[String: [Datum]]]()
    for team in teams {
    let teamProjects = projects.filter {$0.relationships.team.id == team.id}
    let teamData = [team: [teamProjects]]
    teams.append(teamData)
    }
    

    在 numberOfRows 方法中:

     let team = teamsWithProjects[section-1]
     let teamProject = Array(team.values)[0]
     return teamProject.count
    

    在 cellForRow 方法中:

      let team = teamsWithProjects[indexPath.section-1]
      let teamProject = Array(team.values)[0]
      projectCell.textLabel?.text = teamProject[indexPath.row].attributes.name
    

    希望对您有所帮助!

    【讨论】:

    • 谢谢,但在这种情况下这行不通。 (请参阅我更新后的问题,以进一步了解我想要完成的工作)。
    • 而不是硬编码 team1 和 team 2,正如你所展示的,我怎样才能动态地构造这些var teams = [[String:[Project]]]()?注意,这一行对于确保我们在循环中的项目属于团队很重要,在我们将项目添加到该团队之前: // 如果当前项目属于当前团队 if project.relationships.team.id == teams[section - 1].id { ...
    • 谢谢@Hosny - 我们越来越近了。如果我使用var teams = [Included: [Datum]],我得到一个错误Included“不符合协议Hashable。无论如何,我决定我可以使用这个:var teams = [String: [Datum]]。但是当我尝试这样做时:teams.append(teamData),我'得到错误:“类型'[String:[Datum]]'的值没有成员'append'。 teams 是一个字典数组,所以我不确定它为什么不起作用。你知道为什么吗?
    • @diligence,不,团队是字典,对不起,这是我的错,我更新了答案,请检查,我更新为 var teams = [[Included: [Datum]]]。
    • 感谢@Hosny - 感谢您一直以来的帮助。但是即使我使用var teams = [[Included: [Datum]]],我仍然会收到错误消息,“类型'包含'不符合协议'哈希'”。当我使用var teams = [[String: [Datum]]]() 时,没有错误。但是,即使使用这种类型(看起来像字典数组),我也不确定您的其他代码是否会索引出正确的团队项目对。我们可以在 Skype 或 LinkedIn 上联系以更好地讨论这个问题吗?谢谢。
    猜你喜欢
    • 1970-01-01
    • 2020-01-05
    • 1970-01-01
    • 2016-07-06
    • 2018-06-09
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多