Uitableview Swift-如何在两种单元格类型中使用dequeueReusableCellWithIdentifier?(标识符)

Uitableview Swift-如何在两种单元格类型中使用dequeueReusableCellWithIdentifier?(标识符),uitableview,swift,xcode6,Uitableview,Swift,Xcode6,我正在尝试为事件构建一个表视图,如下所示: 我有两个电池原型: 带有标识符“event”的事件单元格 带有标识符“separator”的分隔单元格 另外,我有一个类来表示日期: class Event{ var name:String = "" var date:NSDate? = nil } 这是表格控制器: class EventsController: UITableViewController { //... var eventsToday

我正在尝试为事件构建一个表视图,如下所示:

我有两个电池原型:

  • 带有标识符“event”的事件单元格
  • 带有标识符“separator”的分隔单元格
另外,我有一个类来表示日期:

class Event{

    var name:String = ""
    var date:NSDate? = nil
}
这是表格控制器:

class EventsController: UITableViewController {

    //...

    var eventsToday = [Event]()
    var eventsTomorrow = [Event]()
    var eventsNextWeek = [Event]()

    override func viewDidLoad() {
        super.viewDidLoad()

        //...

        self.fetchEvents()//Fetch events from server and put each event in the right property (today, tomorrow, next week)

        //...
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let event = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell
        let seperator = tableView.dequeueReusableCellWithIdentifier("seperator", forIndexPath: indexPath) as SeperatorTableViewCell

        //...

        return cell
    }
}
我手头有我需要的所有信息,但我想不出正确的方法把它们放在一起。对我来说,重新分类多个单元格类型并不清楚“出列”函数背后的机制

我知道这个问题的范围似乎有点太广了,但是如果有几行代码可以指出正确的方向,我将不胜感激。另外,我认为这会让很多用户受益,因为我没有找到任何快速的例子


提前谢谢

基本方法是,您必须实现
numberofrowsinssection
cellforrowtaindexpath
(如果您的表有多个部分,那么也要实现
numberOfSectionsInTableView
)。但是每次调用
cellforrowatinexpath
都只会创建一个单元格,因此您必须以编程方式执行此操作,查看
indexPath
以确定它是什么类型的单元格。例如,要按照您的建议实现它,它可能如下所示:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return eventsToday.count + eventsTomorrow.count + eventsNextWeek.count + 3 // sum of the three array counts, plus 3 (one for each header)
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var index = indexPath.row

    // see if we're the "today" header

    if index == 0 {
        let separator = tableView.dequeueReusableCellWithIdentifier("separator", forIndexPath: indexPath) as SeparatorTableViewCell

        // configure "today" header cell

        return separator
    }

    // if not, adjust index and now see if we're one of the `eventsToday` items

    index--

    if index < eventsToday.count {
        let eventCell = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell
        let event = eventsToday[index]

        // configure "today" `eventCell` cell using `event`

        return eventCell
    }

    // if not, adjust index and see if we're the "tomorrow" header

    index -= eventsToday.count

    if index == 0 {
        let separator = tableView.dequeueReusableCellWithIdentifier("separator", forIndexPath: indexPath) as SeparatorTableViewCell

        // configure "tomorrow" header cell

        return separator
    }

    // if not, adjust index and now see if we're one of the `eventsTomorrow` items

    index--

    if index < eventsTomorrow.count {
        let eventCell = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell
        let event = eventsTomorrow[index]

        // configure "tomorrow" `eventCell` cell using `event`

        return eventCell
    }

    // if not, adjust index and see if we're the "next week" header

    index -= eventsTomorrow.count

    if index == 0 {
        let separator = tableView.dequeueReusableCellWithIdentifier("separator", forIndexPath: indexPath) as SeparatorTableViewCell

        // configure "next week" header cell

        return separator
    }

    // if not, adjust index and now see if we're one of the `eventsToday` items

    index--

    assert (index < eventsNextWeek.count, "Whoops; something wrong; `indexPath.row` is too large")

    let eventCell = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell
    let event = eventsNextWeek[index]

    // configure "next week" `eventCell` cell using `event`

    return eventCell
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 3
}

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    switch section {
    case 0:
        return "Today"
    case 1:
        return "Tomorrow"
    case 2:
        return "Next week"
    default:
        return nil
    }
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    switch section {
    case 0:
        return eventsToday.count
    case 1:
        return eventsTomorrow.count
    case 2:
        return eventsNextWeek.count
    default:
        return 0
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let eventCell = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell

    var event: Event!

    switch indexPath.section {
    case 0:
        event = eventsToday[indexPath.row]
    case 1:
        event = eventsTomorrow[indexPath.row]
    case 2:
        event = eventsNextWeek[indexPath.row]
    default:
        event = nil
    }

    // populate eventCell on the basis of `event` here

    return eventCell
}

多节方法从表视图更符合逻辑地映射到基础模型,因此我想采用这种模式,但这两种方法都有,您可以决定。

基本方法是必须实现
numberOfRowsInSection
cellforrowatinexpath
(如果您的表有多个部分,
numberOfSectionsInTableView
)。但是每次调用
cellForRowAtIndexPath
只会创建一个单元格,因此您必须以编程方式执行此操作,查看
indexPath
,以确定它是什么类型的单元格。例如,要按照您的建议实现它,它可能如下所示:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return eventsToday.count + eventsTomorrow.count + eventsNextWeek.count + 3 // sum of the three array counts, plus 3 (one for each header)
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var index = indexPath.row

    // see if we're the "today" header

    if index == 0 {
        let separator = tableView.dequeueReusableCellWithIdentifier("separator", forIndexPath: indexPath) as SeparatorTableViewCell

        // configure "today" header cell

        return separator
    }

    // if not, adjust index and now see if we're one of the `eventsToday` items

    index--

    if index < eventsToday.count {
        let eventCell = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell
        let event = eventsToday[index]

        // configure "today" `eventCell` cell using `event`

        return eventCell
    }

    // if not, adjust index and see if we're the "tomorrow" header

    index -= eventsToday.count

    if index == 0 {
        let separator = tableView.dequeueReusableCellWithIdentifier("separator", forIndexPath: indexPath) as SeparatorTableViewCell

        // configure "tomorrow" header cell

        return separator
    }

    // if not, adjust index and now see if we're one of the `eventsTomorrow` items

    index--

    if index < eventsTomorrow.count {
        let eventCell = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell
        let event = eventsTomorrow[index]

        // configure "tomorrow" `eventCell` cell using `event`

        return eventCell
    }

    // if not, adjust index and see if we're the "next week" header

    index -= eventsTomorrow.count

    if index == 0 {
        let separator = tableView.dequeueReusableCellWithIdentifier("separator", forIndexPath: indexPath) as SeparatorTableViewCell

        // configure "next week" header cell

        return separator
    }

    // if not, adjust index and now see if we're one of the `eventsToday` items

    index--

    assert (index < eventsNextWeek.count, "Whoops; something wrong; `indexPath.row` is too large")

    let eventCell = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell
    let event = eventsNextWeek[index]

    // configure "next week" `eventCell` cell using `event`

    return eventCell
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 3
}

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    switch section {
    case 0:
        return "Today"
    case 1:
        return "Tomorrow"
    case 2:
        return "Next week"
    default:
        return nil
    }
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    switch section {
    case 0:
        return eventsToday.count
    case 1:
        return eventsTomorrow.count
    case 2:
        return eventsNextWeek.count
    default:
        return 0
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let eventCell = tableView.dequeueReusableCellWithIdentifier("event", forIndexPath: indexPath) as EventTableViewCell

    var event: Event!

    switch indexPath.section {
    case 0:
        event = eventsToday[indexPath.row]
    case 1:
        event = eventsTomorrow[indexPath.row]
    case 2:
        event = eventsNextWeek[indexPath.row]
    default:
        event = nil
    }

    // populate eventCell on the basis of `event` here

    return eventCell
}

多节方法更符合逻辑地从表视图映射到基础模型,因此我想采用这种模式,但您有两种方法,可以自行决定。

您的代码应该可以正常工作,您只需使用func registerClass(uCellClass:AnyClass,forCellReuseIdentifier标识符:String)来注册这两个“事件”和“分离器”单元格标识符和表视图在某些地方,我在viewDidLoad@user3435374显然,如果使用单元原型,则无需手动注册标识符。但是,此代码没有任何意义。
cellforrowatinedexpath
应仅创建一个单元,具体取决于
nsindepath
@Rob I相信这正是问题所在,Rob。如果该方法只创建一个单元格,您将如何返回两个(或更多)单元格不同类型的单元格?在代码中会是什么样子?@LucasCerro-我在下面的回答的前半部分说明了如何做到这一点。关键的观察结果是,虽然您希望它能够实例化两种类型的单元格,但它对表中的每行调用一次,并且每个单元格只有一种类型。因此,这不是如何实例化的问题两种类型的单元格,但更准确地说,给定一个特定的
nsindepath
,应该实例化这两种类型的单元格中的哪一种。我个人认为这是一种过于复杂的方法,所以在我回答的下半部分,我将介绍一种更简单的方法(至少在本例中)。抱歉,在阅读您的解决方案之前,我阅读了您的评论。您的答案非常完美。代码一点也不令人困惑。相反,您提出了一些优雅的方法来以干巴巴的方式解决问题。感谢您的回答。为我指出其他内容的解决方案,例如部分标题,我获得了额外的荣誉。=)您的代码应该可以正常工作,您所需要做的就是使用func registerClass(cellClass:AnyClass,forCellReuseIdentifier标识符:String)在表视图中注册“事件”和“分隔符”单元格标识符,我在表视图中的某些位置执行此操作viewDidLoad@user3435374显然,如果使用单元原型,则无需手动注册标识符。但是,这段代码没有任何意义。
cellforrowatinexpath
应该只创建一个单元格,这取决于
nsindepath
@Rob我相信这正是问题所在,Rob。如果该方法只创建一个单元格,您将如何返回两个(或更多)不同类型的单元格?这在代码中会是什么样子?@LucasCerro-我在下面回答的前半部分说明了如何做到这一点。关键的观察结果是,虽然您希望它能够实例化两种类型的单元格,但它对表的每一行调用一次,并且每个单元格仅为一种类型。因此,这不是如何实例化两种类型的单元格的问题,而是更准确地说,给定一个特定的
nsindepath
,应该实例化这两种类型的单元格中的哪一种。就我个人而言,我仍然认为这是一种过于复杂的方法,因此在我的回答的后半部分,我将介绍一种更简单的方法(至少在本例中是这样)。对不起,我在阅读解决方案之前阅读了您的评论。你的回答很完美。代码一点也不混乱。相反,您提出了一些优雅的方法,以干巴巴的方式解决它。谢谢你的回答。额外感谢您为我指出了其他内容的解决方案,例如章节标题。=)