如何在uitableview的cellForRowAt函数中按标题日期对响应进行排序

Posted

技术标签:

【中文标题】如何在uitableview的cellForRowAt函数中按标题日期对响应进行排序【英文标题】:How to sort response by header date in cellForRowAt function in uitableview 【发布时间】:2018-07-26 13:12:46 【问题描述】:

我目前有一个来自json 的 json 响应,它是一个 [NSDictionary]。这显示在表格视图中,我能够将排序的日期设置为标题,但是在 cellForRowAt 函数中设置 uilabel 时遇到了困难。我要显示的表格视图有一个已排序日期的标题标题(我已经有),并且在该部分下是与标题具有相同日期的名称。我在下面提供了代码。感谢您的帮助和建议。

import UIKit
import Alamofire

class JSONTableViewController: UITableViewController 



var responseValue:[NSDictionary] = []
var sortedResponsevalue:[NSDictionary] = []
var sectionHeaderArray:[String] = []
var rowTitle:[String] = []

override func viewDidLoad() 
    super.viewDidLoad()


override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)
    for response in self.responseValue 
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let responseDate = response.object(forKey: "date") as! String
        let date = dateFormatter.date(from: responseDate)
        print(date!.toString(dateFormat: "MMM d, yyyy"))
        self.sectionHeaderArray.append(date!.toString(dateFormat: "MMM d, yyyy"))
        self.rowTitle.append(response.object(forKey: "name") as! String)
    
    print(self.sectionHeaderArray.count)


override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? 
    return self.sectionHeaderArray[section]


// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int 
    // #warning Incomplete implementation, return the number of sections
    return self.sectionHeaderArray.count


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return self.sectionHeaderArray[section].count


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return 80



override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "jsonCell", for: indexPath) as! JSONTableViewCell

    if let nameString = self.responseValue[indexPath.row].object(forKey: "name") as? String 
        cell.jsonLabel.text = nameString

    


      return cell
    

【问题讨论】:

【参考方案1】:

我从您的问题中了解到:您在 cellForRow 方法中获得了“nameString”的相同标题。

问题是

if let nameString = self.responseValue[indexPath.row].object(forKey: "name") as? String 
        cell.jsonLabel.text = nameString
    

您传递的部分数量 self.sectionHeaderArray.count。因为总部分 = 100,并且每个部分只有 1 行,所以标题将始终保持不变。

试试这个:使用 indexPath.section 而不是 indexPath.row 来获得不同的标题

if let nameString = self.responseValue[indexPath.section].object(forKey: "name") as? String 
        cell.jsonLabel.text = nameString
    

编辑

class JSONTableViewController: UITableViewController

    var responseValue:[NSDictionary] = []
    var sortedResponsevalue:[NSDictionary] = []
    var sectionHeaderArray = [[String: Any]]()

    override func viewDidLoad() 
        super.viewDidLoad()

    

    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(animated)

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        var currentDate: String? = nil
        var nameArray = [String]()
        for (index,response) in self.responseValue.enumerated() 
            let responseDate = response.object(forKey: "date") as! String
            let date = dateFormatter.date(from: responseDate)
            let dateString = date!.toString(dateFormat: "MMM d, yyyy")
            let nameString = response.object(forKey: "name") as! String
            if currentDate == nil 
                // FIRST TIME
                currentDate = dateString
                nameArray.append(nameString)

             else 
                // CHECK IF DATES EQUAL, THEN KEEP ADDING
                if currentDate == dateString 
                    nameArray.append(nameString)
                    if index == self.responseValue.count - 1 
                        let dictToAppend: [String : Any] = ["date": currentDate!, "names": nameArray]
                        self.sectionHeaderArray.append(dictToAppend)
                    
                 else 
                    let dictToAppend: [String : Any] = ["date": currentDate!, "names": nameArray]
                    self.sectionHeaderArray.append(dictToAppend)
                    currentDate = dateString
                    nameArray.removeAll()
                    nameArray.append(nameString)
                
            
        

    

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? 
        let dictInfo = self.sectionHeaderArray[section]
        let dateString = dictInfo["date"]
        return dateString as? String
    

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int 
        // #warning Incomplete implementation, return the number of sections
        return self.sectionHeaderArray.count
    

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        let dictInfo = self.sectionHeaderArray[section]
        let namesArray = dictInfo["names"] as! [String]

        return namesArray.count
    

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return 80
    


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "jsonCell", for: indexPath) as! JSONTableViewCell

        let dictInfo = self.sectionHeaderArray[indexPath.section]
        let namesArray = dictInfo["names"] as! [String]
        let nameString = namesArray[indexPath.row]
        cell.jsonLabel.text = nameString

        return cell
    

尝试并分享结果。

【讨论】:

我会试试这个。我不确定如何定义 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int return self.sectionHeaderArray[section].count 的返回值 if let nameString = self.responseValue[indexPath.section].object(forKey: "name") as? String cell.jsonLabel.text = nameString 已经为 cellForRowAt 设置了正确的值,但是现在的问题是每个结果的正确行数。感谢您的帮助 numberOfRowsInSection 应该返回 1,因为日期和名称是一对一的映射。 有没有办法根据 json 响应使其动态化?我有 2 件商品,日期为 2018 年 6 月 20 日、2018 年 4 月 26 日、2018 年 4 月 16 日、2018 年 2 月 23 日等。是否可以在同一部分中返回具有相同日期的名称数量?谢谢 你真的救了我。这做得恰到好处。我不能感谢你足够的 Bhavin。感谢您的耐心等待。【参考方案2】:

这是一种不同的方法,使用 Decodable 协议将 JSON 解码为结构,并使用优化的初始化程序 Dictionary(grouping:by:) 按日期对项目进行分组。

创建一个结构体(可以在视图控制器之外)

struct Response : Decodable 
    let id : Int
    let date : Date
    let name : String

在视图控制器内部为标题标题创建一个日期格式化程序

let dateFormatter : DateFormatter = 
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.dateFormat = "MMM d, yyyy"
    return formatter
()

和一个 native 字典(从不NSDictionary)用于数据源和一个数组用于Date 实例的部分。使用Date的好处是可以排序(字符串日期格式无法正确排序)

var sections = [Date]()
var dataSource = [Date:[Response]]()

假设dataviewDidLoad 中的JSON 数据,将data 解码到结构中并填充数据源。 Dictionary(grouping:by:) 方法将Response 的数组分组到一个字典中,以日期为键。

override func viewDidLoad() 
    super.viewDidLoad()

    // put here the code to retrieve the JSON data in the variable `data`
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .formatted(dateFormatter)
    do 
        let result = try decoder.decode([Response].self, from: data)
        dataSource = Dictionary(grouping: result, by: $0.date)
        sections = dataSource.keys.sorted()
        self.tableView.reloadData()
     catch 
        print(error)
    

数据源和委托方法是

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? 
    return dateFormatter.string(from: sections[section])


// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int 
    // #warning Incomplete implementation, return the number of sections
   return sections.count


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    let sectionDate = sections[section]
    return dataSource[sectionDate]!.count


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return 80



override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "jsonCell", for: indexPath) as! JSONTableViewCell

    let sectionDate = sections[indexPath.section]
    let item = dataSource[sectionDate]![indexPath.row]
    cell.jsonLabel.text = item.name

    return cell

【讨论】:

你能帮我解决这个问题吗@vadian only using nsurlsession ***.com/questions/62084188/… @DilipTiwari 抱歉,*** 不是代码编写服务,如何解析 JSON 是 SO 上最常见的问题之一。请搜索。 您遇到了什么问题?您几乎可以按字面意思使用答案。 没有解码我该怎么办

以上是关于如何在uitableview的cellForRowAt函数中按标题日期对响应进行排序的主要内容,如果未能解决你的问题,请参考以下文章

在 tableviewcell 中使用 UITableview 执行 segue

使用 NSSet 关系填充 cellForRow

UITableView 中的自定义单元格重叠

如何在 indexPath 的 cellForRow 中使用多个获取请求结果数组

关于UITableview刷新笔记

不调用UITableView Delegate