Как установить UITableViewCellStyleSubtitle и dequeueReusableCell в Swift?

Я хотел бы использовать UITableView с subtitle -стилами, использующими dequeueReusableCellWithIdentifier.

Мой оригинальный Objective-C код:

static NSString*    reuseIdentifier = @"Cell";
    UITableViewCell*    cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    if(!cell)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
    }

После поиска нескольких вопросов UITableView здесь уже на SO, я подумал записать его в Swift следующим образом:

    tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: "Cell")

    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell

Но это не позволяет мне сказать, что мне нужен стиль subtitle. Поэтому я попробовал это:

var cell :UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")

Что дает мне ячейку subtitle, но она не позволяет мне dequeueReusableCellWithIdentifier.

Я изучил еще несколько и посмотрел этот видеоурок, но он создает отдельный subclass of UITableViewCell, который, как я полагаю, не нужен, поскольку я сделал этот же эффект ранее в Obj-C.

Любые идеи? Спасибо.

Ответ 1

Имейте в виду, что UITableView определяется как необязательный в функции, что означает, что ваша первоначальная декларация ячейки должна проверять наличие необязательного свойства. Кроме того, возвращенная ячейка в очереди также является необязательной, поэтому убедитесь, что вы добавили опцию в UITableViewCell. Впоследствии мы можем заставить разворот, потому что мы знаем, что у нас есть ячейка.

var cell:UITableViewCell? = 
tableView?.dequeueReusableCellWithIdentifier(reuseIdentifier) as? UITableViewCell
if (cell == nil)
{
   cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, 
                reuseIdentifier: reuseIdentifier)
}
// At this point, we definitely have a cell -- either dequeued or newly created,
// so let force unwrap the optional into a UITableViewCell
cell!.detailTextLabel.text = "some text"

return cell

Ответ 2

Если вы предпочитаете избегать дополнительных возможностей, вы можете создать подкласс UITableViewCell, который будет выглядеть примерно так:

class SubtitleTableViewCell: UITableViewCell {

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Затем зарегистрируйте его, используя:

override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.register(SubtitleTableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
}

Это позволяет вашему коду настройки ячейки быть действительно хорошим:

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

    let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)

    cell.textLabel?.text = "foo"
    cell.detailTextLabel?.text = "bar"

    return cell
}

Ответ 3

В основном то же самое, что и другие ответы, но я общаюсь с неприятными опциями (вы не можете вернуть nil из -tableView:cellForRow:atIndexPath: в Swift) с помощью вычисленной переменной:

Swift 3

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

    let cell: UITableViewCell = {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell") else {
            // Never fails:
            return UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: "UITableViewCell")
        }
        return cell
    }()

    // (cell is non-optional; no need to use ?. or !)

    // Configure your cell:
    cell.textLabel?.text       = "Key"
    cell.detailTextLabel?.text = "Value"

    return cell
}

Edit:

На самом деле было бы лучше удалить ячейку с помощью: tableView.dequeueReusableCell(withIdentifier:for:).

Этот более поздний вариант функции автоматически создает новую ячейку, если никто не доступен для повторного использования (именно то, что делает мой код явно выше) и поэтому никогда не возвращает nil.

Ответ 4

Просто основываясь на ответе меммонов, очистив его стиль Swift 2...

let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) ?? UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: reuseIdentifier)

cell.detailTextLabel?.text = "some text"

return cell

Swift 3:

let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) ?? UITableViewCell(style: .subtitle, reuseIdentifier: cellIdentifier)

cell.detailTextLabel?.text = ""

return cell

Ответ 5

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let reuseIdentifier = "cell"
    var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) as UITableViewCell?
    if (cell == nil) {
        cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: reuseIdentifier)
    }
    cell!.textLabel?.text = self.items[indexPath.row]
    cell!.detailTextLabel?.text = self.items[indexPath.row]
    return cell!
}

Ответ 6

Так как tableView.dequeueReusableCell(withIdentifier:, for:) возвращает ячейку non-nil, проверка if cell == nil всегда будет ложной. Но я нашел решение, чтобы ячейка стиля по умолчанию стала тем стилем (value1, value2 или subtitle), который вы хотите, потому что ячейка стиля стиля detailTextLabel равна нулю, поэтому проверьте detailTextLabel, если она равна нулю, затем создайте новую ячейку стиля, и дать ему деактивировать ячейку, например:

Swift 3:

var cell = tableView.dequeueReusableCell(withIdentifier: yourCellReuseIdentifier, for: indexPath)

if cell.detailTextLabel == nil {
    cell = UITableViewCell(style: .value1, reuseIdentifier: repeatCellReuseIdentifier)
}

cell.textLabel?.text = "Title"
cell.detailTextLabel?.text = "Detail"

return cell

Это работает для меня.

Надеюсь, что это поможет.

Ответ 7

Для предотвращения принудительной разворачивания вы можете использовать несколько иной синтаксис, отличный от memmons:

let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) as? UITableViewCell ?? UITableViewCell(style: .Subtitle, 
            reuseIdentifier: reuseIdentifier)

cell.detailTextLabel?.text = "some text"

return cell

Это использует XCode 6.1 7, Swift 1.2 2.0, где UITableView больше не является необязательным.

Ответ 8

Если вы не используете свою собственную пользовательскую ячейку. Просто зарегистрируйте UITableViewCell через код. Тогда вы можете выбрать код.

Просто выберите раскадровку, выберите свой TableViewCell → Goto Attribute Inspector и выберите нужный стиль, как показано ниже.

введите описание изображения здесь

Ответ 9

Идеально, как предложил Майкл Дж. Эммонс, но в Xcode 6.1, используя

if !cell { .....

Я получаю эту ошибку:

Необязательный тип '@| значение UITableViewCell?' не может использоваться как логическое; тест вместо '!= nil'

Принятый синтаксис:

if cell == nil { ...

Ответ 10

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath:
 NSIndexPath) -> UITableViewCell {  
     var CellIdentifier:String = "Cell"  
     var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as? UITableViewCell  
     if cell == nil {  
        cell = UITableViewCell(style:UITableViewCellStyle(rawValue:3)!,reuseIdentifier:CellIdentifier)   
      }
    return cell!
}

Ответ 11

Это немного странно. Я ожидал бы, что tableView потребует от нас вернуть ячейку, которая была зарегистрирована на ней с помощью идентификатора ячейки. Но это, похоже, не так, и следующее отобразит ячейку для textLabel и detailTextLabel:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = UITableViewCell(style: .Subtitle, reuseIdentifier: cellId)    
    let user = users[indexPath.row]
    cell.textLabel?.text = user.name
    cell.detailTextLabel?.text = user.email
    return cell
}

Ответ 12

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

    var cell:UITableViewCell? =
        tableView.dequeueReusableCell(withIdentifier: "cell")
    if (cell != nil)
    {
        cell = UITableViewCell(style: UITableViewCellStyle.subtitle,
                               reuseIdentifier: "cell")
    }
    cell!.textLabel?.text = "ABC"
    cell!.detailTextLabel?.text = "XYZ"

    return cell!

  }

Ответ 13

Убедитесь, что вы не регистрируете ни одну ячейку в табличном представлении.

Если вы это сделали, dequeueReusableCellWithIdentifier всегда будет давать необязательную ячейку, поэтому UITableViewCellStyle.Subtitle никогда не будет инициироваться.

Ответ 14

Я приглашаю вас посмотреть этот маленький пример UITableView на Github: https://github.com/YANGReal/UITableView-Swift

Они делают следующее:

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
   let cell = tableView .dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
   cell.textLabel.text = String(format: "%i", indexPath.row+1)
   // set any other property of your cell here
   return cell
}

Ответ 15

Просто используйте это для Swift 3:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "My Reuse Identifier", for: indexPath)

    cell.textLabel?.text = "Key"
    cell.detailTextLabel?.text = "Value"

    return cell
}

Ответ 16

swift4:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = settingsTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    cell.textLabel?.text = "String"
    cell.detailTextLabel?.text = " string"
    return cell
}