Обновление UILabel из обработчика UIAlertAction не работает в Swift 4

У меня есть подкласс UITableView в моем приложении для iOS (Swift 4, XCode 9). Эта таблица имеет одну строку, и я хочу, чтобы она отображала предупреждение при нажатии, получала некоторую информацию от пользователя, а затем обновляла метку (lblUserFromPrefs) в таблице, когда пользователь нажимал «ОК» в предупреждении. В настоящее время все работает нормально, за исключением того, что метка не обновляется. Вот соответствующий код из моего подкласса UITableView:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print("Clicked section: \(indexPath.section) row: \(indexPath.row)")
    let alert = UIAlertController(title: "Username", message: "what is your name", preferredStyle: .alert)

    alert.addTextField { (textField) in
        textField.text = ""
    }
    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
        let textField = alert!.textFields![0]
        if let text = textField.text {
            print("Text field: \(text)")
            DispatchQueue.main.async {
                self.lblUserFromPrefs.text = text
                print("label updated")
            }
        }
    }))

    DispatchQueue.main.async {
        self.present(alert, animated: true, completion: nil)
    }
}

Что происходит, когда я запускаю это, так это то, что текст метки не меняется, когда предупреждение закрывается, но изменяется сразу же, когда строка таблицы снова щелкается. Я не знаю, почему он ждет, пока строка не будет снова нажата, чтобы обновить текст. Все операторы печати печатаются, когда я ожидаю (включая печать «обновленной метки» сразу после нажатия кнопки «ОК» предупреждения), и они печатают правильные вещи. Я знаю, что когда вы пытаетесь обновить пользовательский интерфейс из закрытия в фоновом потоке, вы должны использовать DispatchQueue.main.async {}, но я не уверен, почему он не обновляется, хотя я использую основной поток. Я пробовал использовать DispatchQueue.main.async(execute: {}) и ставить self.lblUserFromPrefs.setNeedsDisplay() сразу после self.lblUserFromPrefs.text = "text". Любые идеи, что я делаю неправильно? Спасибо!!


person Cory Matthews    schedule 04.06.2019    source источник
comment
Вам не нужно звонить DispatchQueue, все равно ваша проблема выглядит как [weak alert]. См. этот ответ   -  person Mannopson    schedule 05.06.2019
comment
@Mannopson Я удалил оболочку DispatchQueue и изменил [weak alert] на (action) in, но он по-прежнему ведет себя так же. Что именно из этой ссылки я должен посмотреть? Я не пытаюсь вызвать оповещение из этого оповещения, я просто не могу заставить этот UILabel обновляться в нужное время. Спасибо за помощь!   -  person Cory Matthews    schedule 05.06.2019


Ответы (3)


Добавьте [weak self] в рассылку следующим образом:

DispatchQueue.main.async { [weak self] in

}
person Mauricio Martinez    schedule 04.06.2019
comment
@CoryMatthews Я скопировал ваш код, и он сработал, так что проблемы нет. - person Mauricio Martinez; 06.06.2019

Попробуйте что-то вроде этого:

let alertController = UIAlertController.init(title: "Enter some text", message: nil, preferredStyle: .alert)
    alertController.addTextField { (textField) in

        // Text field configuration
        textField.placeholder = "Enter..."
        textField.text = ""
    }

    alertController.addAction(UIAlertAction.init(title: "Ok", style: .default, handler: { (action) in
        if (alertController.textFields?.first?.hasText)! {
            if let text = alertController.textFields?.first?.text {
                self.label.text = text // Update the value
            }
        } else {
            self.label.text = "" // Default value
        }
    }))

    self.present(alertController, animated: true, completion: nil) // Present alert controller
person Mannopson    schedule 05.06.2019
comment
К сожалению, все еще такое же поведение. - person Cory Matthews; 05.06.2019
comment
Я думаю, что проблема связана с использованием статических ячеек в UITableView, но я не уверен, как обновить UILabel в статическом UITableView в режиме реального времени. - person Cory Matthews; 05.06.2019

Вот пример кода поведения, которого вы хотите добиться. Просто включите код контроллера предупреждений в didSelect, и все готово!

import UIKit
import PlaygroundSupport

class MyViewController : UITableViewController {

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

  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
  }

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
    if cell == nil {
      cell = UITableViewCell()
    }
    cell!.textLabel?.text = "Hello World!"
    return cell!
  }

  override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath)
    cell?.textLabel?.text = "Hello Universe!"
  }
}
person Swapnil Jain    schedule 07.06.2019