【问题标题】:Sectioning UITableView cells分割 UITableView 单元格
【发布时间】:2016-07-04 06:37:53
【问题描述】:

我正在尝试将我的 tableview 单元格从列表中的项目元素 (dueTime) 中组织成部分。 Firebase 是我的后端,每个项目都有一个名为 dueTime 的子节点,其中包含时间字符串。我已经创建了这些部分并让它们出现,但我需要将实际项目分开。目前,当我运行我的代码时,只显示部分。

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        let tasksRef = ref.childByAppendingPath("tasks")
        tasksRef.observeSingleEventOfType(.Value, withBlock: {snapshot in
            var dueTimesArray = [String]()
            for task in snapshot.children.allObjects as! [FDataSnapshot] {
                let times = task.value["dueTime"] as! String
                dueTimesArray.append(times)
            }
            self.sectionTimes = dueTimesArray
        })
        let uniqueSectionTimes = Array(Set(sectionTimes))
        return uniqueSectionTimes.count
    }


    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        var uniqueSectionTimes = Array(Set(sectionTimes))
        let tasksRef = Firebase(url: "\(self.ref)/tasks")
        tasksRef.queryOrderedByChild("dueTime").queryEqualToValue(uniqueSectionTimes[section]).observeEventType(.Value, withBlock: { snapshot in
            var newTasks = [Task]()
            for task in snapshot.children.allObjects as! [FDataSnapshot] {
                let tasks = Task(snapshot: task)
                newTasks.append(tasks)
            }
            self.sectionTasks = newTasks
        })
        return self.sectionTasks.count
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! TaskCell

        // Configure the cell...
        cell.selectionStyle = .None
//        let uniqueSectionTimes = Array(Set(sectionTimes))
//        let times = self.sectionTasks[uniqueSectionTimes[indexPath.section]]
        let task = tasks[indexPath.row]
        cell.label.text = task.title
        ref.childByAppendingPath("tasks").observeEventType(.Value, withBlock: { snapshot in
        if task.done == true {
            cell.checkBox.image = UIImage(named: "checkedbox")
            cell.detailLabel.text = "Completed By: \(task.completedBy)"
            }
            else {
            cell.checkBox.image = UIImage(named: "uncheckedbox")
            cell.detailLabel.text = ""
            }
        })

        cell.delegate = self
        return cell
    }

    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        let uniqueSectionTimes = Array(Set(sectionTimes))

        return uniqueSectionTimes[section]
    }

我觉得问题的根源可能在 numberOfRowsInSection 和 cellForRowAtIndexPath 中。从 numberOfRowsInSection 中,当我将 self.sectionTasks 设置为等于 newTasks 后打印时,我得到 6 个数组(等于节数),所有正确的任务都在正确的数组中。但是,当我打印self.sectionTasks.count时,我得到了六次'0',这对我来说没有意义。我不知道在cellForRowAtIndexPath 中该做什么。我似乎在任何地方都找不到很好的教程来解释它。

更新 1:

我在numberOfRows也试过这个

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        var uniqueSectionTimes = Array(Set(sectionTimes))
        let tasksRef = Firebase(url: "\(self.ref)/tasks")
        tasksRef.queryOrderedByChild("dueTime").queryEqualToValue(uniqueSectionTimes[section]).observeEventType(.Value, withBlock: { snapshot in
            var newTasks = [String]()
            for task in snapshot.children.allObjects as! [FDataSnapshot] {
                let tasks = task.value["title"] as! String
                newTasks.append(tasks)
            }
//            for task in snapshot.children.allObjects as! [FDataSnapshot] {
//                let tasks = Task(snapshot: task)
//                newTasks.append(tasks)
//            }
            self.sectionTasks = newTasks
        })
        print(sectionTasks.count)
        return self.sectionTasks.count
    }

我得到了同样的结果。基本上,这种方式只给了我项目的标题,而不是每个数组中的整个项目。但它仍然告诉我所有数组的计数都是 0。

更新 2:

在实现以下代码后,我现在可以在每个部分下重复所有任务。我想我需要以某种方式过滤任务,但我不确定在哪里或如何做到这一点。

 func queryDueTimes(uniqueSectionTimes:Array<String>) {
        let tasksRef = Firebase(url: "\(self.ref)/tasks")
        tasksRef.queryOrderedByChild("dueTime").observeEventType(.Value, withBlock: { snapshot in
            var newTasks = [Task]()
            for task in snapshot.children.allObjects as! [FDataSnapshot] {
                let times = Task(snapshot: task)
                newTasks.append(times)
            }
            self.sectionTasks = newTasks
            print(self.sectionTasks)
            self.tableView.reloadData()
        })
    }

我在viewDidLoad() 中运行这个函数,并得到一个包含每个任务的所有元素的大数组。我想我需要使用numberOfRows 中的“section”元素,但我不确定如何使用。此外,我正在查看的教程显示了 indexPath.section 在cellForRow 中的使用,但我只是不确定如何实现其中任何一个。

解决方案:

我最终完全更改了查询代码,因此我从本地数组而不是 Firebase 中提取。

func querySections() -> [String] {
           var sectionsArray = [String]()
        for task in tasks {
            let dueTimes = task.dueTime
            sectionsArray.append(dueTimes)
        }
        let uniqueSectionsArray = Array(Set(sectionsArray)).sort()
        return uniqueSectionsArray
    }


    func queryDueTimes(section:Int) -> [Task] {
        var sectionItems = [Task]()
        for task in tasks {
            let dueTimes = task.dueTime
            if dueTimes == querySections()[section] {
                sectionItems.append(task)
            }
        }
        return sectionItems
    }



    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return querySections().count
    }



    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return queryDueTimes(section).count
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! TaskCell

        // Configure the cell...
        cell.selectionStyle = .None
        let times = queryDueTimes(indexPath.section)
        let task = times[indexPath.row]
        cell.label.text = task.title
        if task.done == true {
            cell.checkBox.image = UIImage(named: "checkedbox")
            cell.detailLabel.text = "Completed By: \(task.completedBy)"
            }
            else {
            cell.checkBox.image = UIImage(named: "uncheckedbox")
            cell.detailLabel.text = ""
            }

        cell.delegate = self
        return cell
    }

    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return querySections()[section]
    }

【问题讨论】:

  • 当我看到将块作为参数的调用时,我怀疑它们可能是异步的。 observeEventType 函数是这样吗?如果是这样,您可能会在完成任务之前返回一个计数。(尝试在块内放置另一个打印以确认事件的顺序。)
  • 有许多可用的 UITableView 教程,所以我首先建议在引入 Firebase 方面之前先熟悉创建一个使用静态数据填充 tableView 的方法。 cellForRowAtIndexPath 允许表格重新使用它已经创建的单元格,因此避免必须为每个需要的单元格分配、初始化等一个新单元格。总体情况是,您需要在尝试填充表格之前分别从 Firebase 读取数据。此外,如果您要向 Firebase 添加观察者,则每次发生事件时,您都需要清除数组和表格并重新填充它。
  • 我很乐意填充 tableView。我了解 cellForRow 的作用以及如何使用它。我的问题是合并这些部分。

标签: ios arrays swift uitableview firebase


【解决方案1】:

发生这种情况是因为对taskRef.query... 的调用是异步的。而numberOfRowsInSection 方法要求此时您已经知道您拥有的行数。

将查询代码移动到其他方法中,例如

func queryDueTimes(uniqueSectionTimes: Array) { 
    let tasksRef = Firebase(url: "\(self.ref)/tasks")
            tasksRef.queryOrderedByChild("dueTime").queryEqualToValue(uniqueSectionTimes[section]).observeEventType(.Value, withBlock: { snapshot in
                var newTasks = [String]()
                for task in snapshot.children.allObjects as! [FDataSnapshot] {
                    let tasks = task.value["title"] as! String
                    newTasks.append(tasks)
                }
    //            for task in snapshot.children.allObjects as! [FDataSnapshot] {
    //                let tasks = Task(snapshot: task)
    //                newTasks.append(tasks)
    //            }
                self.sectionTasks = newTasks


               //IMPORTANT: reload your table here:
                self.tableView.reloadData()
            })
}

然后,从视图控制器的viewDidLoad() 方法调用queryDueTimes 方法:

func viewDidLoad()
{
    super.viewDidLoad()

    var uniqueSectionTimes = Array(Set(sectionTimes))
    self.queryDueTimes(uniqueSectionTimes)
}

【讨论】:

  • 按原样,我收到有关 queryDueTimes 函数第一行的错误,因此我将其更改为 (uniqueSectionTimes:Array) 但现在我无法访问 queryEqualToValue 中的“部分” .有什么想法吗?
  • 您应该请求完整的数据集,而不是按部分。或者,您可以在此处请求您拥有的所有部分并按部分存储它们,当您收到所有响应时 - 重新加载表格。
  • 我更新了帖子以包含我的最新一期。如何使用 section 元素将任务实际过滤到不同的 section 数组中,如何在 cellForRow 中使用 indexPath.section?
  • 为了确保您理解我的正确:有两种可能性 - 一种是获取完整的数据集并手动将其按部分拆分(如果您知道如何)。第二 - 是请求每个部分的数据集。看起来您实现了第一种方法,但您不知道如何按部分拆分它。我认为没有人熟悉您的数据,也没有人能比您更了解这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多