在 Swift 中点击 return 键时,如何关闭 UIAlertController?

How do I dismiss a UIAlertController when the return key is tapped in Swift?

我有一个带有两个按钮和一个文本字段的 UIAlertController。当保存按钮被点击时,一个 segue 被执行。我还在 textFieldShouldReturn 中设置了 return 键来执行此操作。但是,当 return 键被点击时,警报控制器不会关闭。它向上移动到视图的左上角,并导致动画在返回视图时挂起。我还尝试使用 myAlertController.dismiss(animated: false, completion: nil) 关闭警报控制器,但这会引发 "Attempt to present a UINavigationController on a UIAlertController whose view is not in the window hierarchy" 错误。当 return 键被点击并仍然执行 segue 时,如何关闭警报控制器?谢谢。

import UIKit
import CoreData

var albumNameFromTextfield: String = ""

class AlbumViewController: UIViewController, UITextFieldDelegate {

// MARK: - Properties
@IBOutlet weak var albumCollectionView: UICollectionView!
@IBOutlet weak var noAlbumsView: UIView!

var albums: [NSManagedObject] = []

let newAlbumAlert = UIAlertController(title: "Create New Album", message: "Enter a name for your new album.", preferredStyle: UIAlertControllerStyle.alert)

// MARK: - Actions

@IBAction func unwindToAlbumsScreen(sender: UIStoryboardSegue) {
}

@IBAction func newAlbumTapped(_ sender: UIBarButtonItem) {
    createNewAlbum()
}

func createNewAlbum() {
    let nAA = newAlbumAlert
    present(nAA, animated: true, completion: nil)
}

// Alert controller setup
func createNewAlbumAlert() {
    let saveAction = UIAlertAction(title: "Save", style: .default, handler: { (action) in
        guard let textField = self.newAlbumAlert.textFields?[0],
            let nameToSave = textField.text else {
                return
        }
        print("Album name has been inputted; save button tapped.")
        self.save(name: nameToSave)
        self.albumCollectionView.reloadData()
        self.performSegue(withIdentifier: "showNewAlbumViewController", sender: self)
    })

    newAlbumAlert.addTextField{ (textField: UITextField) in
        textField.placeholder = "Album Name"
        textField.keyboardType = .default
        textField.autocorrectionType = .default
        textField.returnKeyType = .done
        textField.delegate = self
        textField.enablesReturnKeyAutomatically = true
    }

    newAlbumAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    newAlbumAlert.addAction(saveAction)

}

//Text field functions
func textFieldDidBeginEditing(_ textField: UITextField) {
    self.newAlbumAlert.actions[1].isEnabled = false
    textField.text = ""
}

func textFieldDidEndEditing(_ textField: UITextField) {
    albumNameFromTextfield = textField.text!
    print("Album name for nav title set.")
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    let TFNameToSave = textField.text
    self.save(name: TFNameToSave!)
    self.albumCollectionView.reloadData()
    textField.resignFirstResponder()
    self.performSegue(withIdentifier: "segueForTF", sender: self)
    print("Album name has been inputted; return button tapped.")
    return true
}

@objc func editingChanged(_ textField: UITextField) {
    if textField.text?.count == 1 {
        if textField.text?.first == " " {
            textField.text = ""
            return
        }
    }
    guard
        let alertControllerText = newAlbumAlert.textFields![0].text, !alertControllerText.isEmpty
    else {
        newAlbumAlert.actions[1].isEnabled = false
        return
    }
    newAlbumAlert.actions[1].isEnabled = true
}

// ViewDidLoad and ViewWillAppear
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    //Core Date functions
    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else {
            return
    }
    let managedContext =
        appDelegate.persistentContainer.viewContext
    let fetchRequest =
        NSFetchRequest<NSManagedObject>(entityName: "Album")
    do {
        albums = try managedContext.fetch(fetchRequest)
    } catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
    }

    //Setup to do when the view will appear
    self.albumCollectionView.reloadData()

    if albums.count == 0 {
        noAlbumsView.alpha = 1
    } else {
        noAlbumsView.alpha = 0
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    createNewAlbumAlert()
    newAlbumAlert.textFields![0].addTarget(self, action: #selector(editingChanged), for: .editingChanged)
}

//Core Data functions
func save(name: String) {
    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else {
            return
    }
    let managedContext =
        appDelegate.persistentContainer.viewContext
    let entity =
        NSEntityDescription.entity(forEntityName: "Album",
                                   in: managedContext)!
    let albumName = NSManagedObject(entity: entity,
                                    insertInto: managedContext)
    albumName.setValue(name, forKeyPath: "albumName")
    do {
        try managedContext.save()
        albums.append(albumName)
    } catch let error as NSError {
        print("Could not save. \(error), \(error.userInfo)")
    }
  }
}

不要在 myAlertController 上调用 dismiss,而是尝试在 AlbumViewController 上调用 dismiss。我在下面编辑了您的 textFieldShouldReturn 函数:

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    let TFNameToSave = textField.text
    self.save(name: TFNameToSave!)
    self.albumCollectionView.reloadData()
    textField.resignFirstResponder()
    // ViewController should dismiss the alert controller
    dismiss(animated: true) {
        self.performSegue(withIdentifier: "segueForTF", sender: self)
        print("Album name has been inputted; return button tapped.")
    }
    return true
}

来自 the docs

The presenting view controller is responsible for dismissing the view controller it presented.

在这里,presenting view controller 应该是 AlbumViewControllerpresentedmyAlertController.

希望有用!