У меня возникла странная проблема, и, возможно, это всего лишь нехватка знаний о Swift 3.0/iOS 10, поэтому, надеюсь, вы можете направлять меня в правильном направлении или объяснять меня то, что я делаю неправильно.Утилита UIAlertController не может вызвать делегат UITextField или целевой объект, но работает в UIViewController
КАК ЭТО РАБОТАЕТ НАСТОЯЩЕЕ
Я пытаюсь создать UIAlertController со стилем .alert, так что я могу получить ввод текста пользователя для моего приложения. Мои требования заключаются в том, что текст не должен быть пустым, и если раньше там был текст, он должен быть другим.
я могу использовать следующий код, чтобы достичь того, чего я хочу:
//This function gets called by a UIAlertController of style .actionSheet
func renameDevice(action: UIAlertAction) {
//The AlertController
let alertController = UIAlertController(title: "Enter Name",
message: "Please enter the new name for this device.",
preferredStyle: .alert)
//The cancel button
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
//The confirm button. Make sure to deactivate on first start
let confirmAction = UIAlertAction(title: "Ok", style: .default, handler: { action in
self.renameDevice(newName: alertController.textFields?.first?.text)
})
//Configure the user input UITextField
alertController.addTextField { textField in
log.debug("Setting up AlertDialog target")
textField.placeholder = "Enter Name"
textField.text = self.device.getName()
textField.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: .editingChanged)
}
//Disable the OK button so that the user first has to change the text
confirmAction.isEnabled = false
self.confirmAction = confirmAction
//Add the actions to the AlertController
alertController.addAction(cancelAction)
alertController.addAction(confirmAction)
present(alertController, animated: true, completion: nil)
}
var confirmAction: UIAlertAction?
func textFieldDidChange(_ textField: UITextField){
log.debug("IT CHAGNED!=!=!=!=!")
if let text = textField.text {
if !text.isEmpty && text != self.device.getName() {
confirmAction?.isEnabled = true
return
}
}
confirmAction?.isEnabled = false
}
//Finally this code gets executed if the OK button was pressed
func renameDevice(newName: String?){ ... }
КАК Я хочу работать
До сих пор так хорошо, но я собираюсь спросить у пользователя текстовый ввод в разных местах, поэтому я хочу использовать служебный класс для обработки всего этого для меня. Последний вызов должен выглядеть следующим образом:
func renameDevice(action: UIAlertAction) {
MyPopUp().presentTextDialog(title: "Enter Name",
message: "Please enter the new name for this device.",
placeholder: "New Name",
previousText: self.device.getName(),
confirmButton: "Rename",
cancelButton: "Cancel",
viewController: self){ input: String in
//do something with the input, e. g. call self.renameDevice(newName: input)
}
ЧТО Я Придумал
Так я реализовал все, что в этом маленьком классе:
class MyPopUp: NSObject {
var confirmAction: UIAlertAction!
var previousText: String?
var textField: UITextField?
func presentTextDialog(title: String, message: String?, placeholder: String?, previousText: String?, confirmButton: String, cancelButton: String, viewController: UIViewController, handler: ((String?) -> Swift.Void)? = nil) {
//The AlertController
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
//The cancel button
let cancelAction = UIAlertAction(title: cancelButton, style: .cancel)
//The confirm button. Make sure to deactivate on first start
confirmAction = UIAlertAction(title: confirmButton, style: .default, handler: { action in
handler?(alertController.textFields?.first?.text)
})
//Configure the user input UITextField
alertController.addTextField { textField in
log.debug("Setting up AlertDialog target")
self.textField = textField
}
//Set placeholder if necessary
if let placeholder = placeholder {
self.textField?.placeholder = placeholder
}
//Set original text if necessary
if let previousText = previousText {
self.textField?.text = previousText
}
//Set the target for our textfield
self.textField?.addTarget(self, action: #selector(textChanged), for: .editingChanged)
log.debug("It appears that our textfield \(self.textField) has targets: \(self.textField?.allTargets)")
//Store the original text for a later comparison with the new entered text
self.previousText = previousText
//Disable the OK button so that the user first has to change the text
confirmAction.isEnabled = false
//Add the actions to the AlertController
alertController.addAction(cancelAction)
alertController.addAction(confirmAction)
viewController.present(alertController, animated: true, completion: nil)
}
func textChanged() {
if let text = textField?.text {
if !text.isEmpty && text != previousText {
confirmAction.isEnabled = true
return
}
}
confirmAction.isEnabled = false
}
}
ПРОБЛЕМА
Моя проблема заключается в том, что независимо от того, где я пытаюсь установить цель для UITextField t он UIAlertController, он никогда не выполняет мою цель. Я попытался установить делегат TextFields в alertController.addTextField {}, а также установить там цель. Проблема, которая меня смущает больше всего, заключается в том, что установка заполнитель и оригинальный текст работает просто отлично, но функции делегирования или целевые функции никогда не вызываются. Почему же тот же код работает при выполнении в UIViewController, но не работает, когда выполняется в классе утилиты?
РЕШЕНИЕ (ДОПОЛНЕНО)
Видимо, я сделал ошибку. В моем контроллере view я создаю экземпляр MyPopUp и вызываю функцию present() на нем.
MyPopUp().presentTextDialog(title: "Enter Name",
message: "Please enter the new name for this device.",
placeholder: "New Name",
previousText: self.device.getName(),
confirmButton: "Rename",
cancelButton: "Cancel",
viewController: self)
В presentTextDialog() Я думал, что установка текущего экземпляра MyPopUp в качестве делегата/цели будет достаточно, но, кажется, что экземпляр MyPopUp освобождается сразу, и поэтому никогда не называл. Мое очень простое решение - создать экземпляр MyPopUp в переменной экземпляра и вызвать настоящий метод всякий раз, когда мне нужно.
let popup = MyPopUp()
func renameDevice(action: UIAlertAction) {
popup.presentTextDialog(...){ userinput in
renameDevice(newName: userinput)
}
}
, в каком классе вам нужно позвонить своему делегату или цели? – KKRocks
Вы покажете класс контроллера вида, где вы пытаетесь вызвать этих делегатов? – User511
Из моего класса UIViewController я хочу сделать вызов MyPopUp(). PresentTextDialog (...) {input in} – xxtesaxx