ios - 尝试在已经呈现的 View Controller 上呈现 UIAlertController(空)[Swift]

标签 ios swift uialertview uialertcontroller

我有一个警告 View ,我正试图在照片 View 上呈现。

照片显示在列表中,可以推送到全屏 View 。

照片 View 正在以编程方式显示。我认为这就是导致问题的原因,因为警报 View 试图在已经呈现的(照片) View 之上呈现另一个 View 。

警报 View 正在尝试显示,但出现此错误:

Warning: Attempt to present <UIAlertController: 0x147d2c6b0>  on <LiveDeadApp.ListViewController: 0x147d614c0> which is already presenting (null)

可能有问题的是这一行:

 self.present(textPrompt, animated: true, completion: nil)

这是主 ListView This is the main list view

这是截图时的主 ListView This is the main list view when a screenshot is taken

这是主照片 View This is the main photo view

这是主照片 View 中的弹出窗口(通过“i”按钮访问) This is the popover in the main photo view (accessed via the "i" button)

在主照片 View 上截取屏幕截图时,不会出现警报 View 。但是,当设备的方向发生变化时,照片 View 会返回到列表并显示警报。 When a screenshot is taken on the main photo view, no alert view occurs. However, when the device's orientation is changed, the photo view goes back to the list and shows the alert.

这就是我想要做的: enter image description here

iOS 10 中的 Swift 3

谢谢!

这是 ListView 和照片 View 的代码:

import UIKit
import Kingfisher
import SKPhotoBrowser

class ListViewCell: UITableViewCell {

@IBOutlet weak var Cellimage: UIImageView!

@IBOutlet weak var cellVenue: UILabel!

@IBOutlet weak var cellLocation: UILabel!

@IBOutlet weak var cellDate: UILabel!
@IBOutlet weak var aiView: UIActivityIndicatorView!
}

class ListViewController: UITableViewController {

var subcategory:Subcategory!

var objects:[[String:String]] = [[String:String]]()

var images = [SKPhotoProtocol]()



override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)


}

override func viewDidLoad() {
    super.viewDidLoad()


    self.tableView.separatorStyle = .none

    self.view.backgroundColor = UIColor.black

    self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]

    navigationController!.navigationBar.barTintColor = UIColor.black

    let requireTextInput = "require text input"
    // add observer for screen shot
    NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationUserDidTakeScreenshot, object: nil, queue: OperationQueue.main, using:
        { notification in

            self.definesPresentationContext = true

            var inputTextField = UITextField()

            let textPrompt = UIAlertController(title: "Test!", message: "Testing!", preferredStyle: .alert)

            textPrompt.addAction(UIAlertAction(title: "Continue", style: .default, handler: {
                (action) -> Void in
                // if the input match the required text

                let str = inputTextField.text
                if str == requireTextInput {
                    print("right")
                } else {
                    print("wrong")
                }

            }))

            textPrompt.addTextField(configurationHandler: {(textField: UITextField!) in
                textField.placeholder = ""
                inputTextField = textField

            })

            self.present(textPrompt, animated: true, completion: nil)

    })

    if subcategory != nil {
        self.title = subcategory.title
        self.objects = subcategory.photos

        createLocalPhotos()

        self.tableView.reloadData()
    }


}

func createLocalPhotos() {

    for item in objects {
        let photo = SKPhoto.photoWithImageURL(item["url"]!)
        photo.shouldCachePhotoURLImage = true
        images.append(photo)
    }

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

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

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

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

    let cell: ListViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! ListViewCell

    let item = objects[indexPath.row]

    let title = item["title"]
    let location = item["location"]
    let date = item["date"]
    let urlSrt = item["url"]


    cell.cellVenue.text = title
    cell.cellLocation.text = location
    cell.cellDate.text = date

    if let url = URL(string: urlSrt!) {
        cell.aiView.startAnimating()
        cell.Cellimage.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: nil, completionHandler: { (image, error, cacheType, url) in
            cell.aiView.stopAnimating()
        })
    }

    return cell

}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath) as! ListViewCell

    if(cell.Cellimage.image != nil ) {
        SKPhotoBrowserOptions.displayToolbar = false
        SKPhotoBrowserOptions.displayCounterLabel = false
        SKPhotoBrowserOptions.displayBackAndForwardButton = false
        SKPhotoBrowserOptions.displayAction = false
        SKPhotoBrowserOptions.displayDeleteButton = true
        SKPhotoBrowserOptions.displayHorizontalScrollIndicator = false
        SKPhotoBrowserOptions.displayVerticalScrollIndicator = false
        SKPhotoBrowserOptions.displayStatusbar = false
        SKPhotoBrowserOptions.disableVerticalSwipe = true
        SKPhotoBrowserOptions.bounceAnimation = false
        let browser = ExtendedSKPhotoBrowser(originImage: cell.Cellimage.image!, photos: images, animatedFromView: cell)

        let btnSize = 80//24 * UIScreen.main.scale

        browser.updateCloseButton(UIImage(named: "ic_close_white")!, size: CGSize(width: btnSize, height: btnSize))
        browser.updateDeleteButton(UIImage(named: "ic_info_white")!, size: CGSize(width: btnSize, height: btnSize))
        browser.initializePageIndex(indexPath.row)
        browser.delegate = self
        present(browser, animated: true, completion: {})
        browser.toggleControls()
    }
}

override var prefersStatusBarHidden: Bool {
    get {
        return true
    }
}


var popOverVC:PopUpViewController!
}

extension ListViewController: SKPhotoBrowserDelegate {
func didShowPhotoAtIndex(_ index: Int) {






}

func willDismissAtPageIndex(_ index: Int) {

}

private func willShowActionSheet(photoIndex: Int) {
    // do some handle if you need
}

func didDismissAtPageIndex(_ index: Int) {
}

func didDismissActionSheetWithButtonIndex(_ buttonIndex: Int, photoIndex: Int) {
    // handle dismissing custom actions
}

func removePhoto(_ browser: SKPhotoBrowser, index: Int, reload: (() -> Void)) {
    popOverVC = self.storyboard?.instantiateViewController(withIdentifier: "sbPopUpID") as! PopUpViewController
    popOverVC.photoData = objects[index]

}

func viewForPhoto(_ browser: SKPhotoBrowser, index: Int) -> UIView? {
    return tableView.cellForRow(at: IndexPath(row: index, section: 0))
}
}


open class ExtendedSKPhotoBrowser: SKPhotoBrowser {

open override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent // white statusbar, .default is black
}

open override var prefersStatusBarHidden: Bool {
    return true
}
}

最佳答案

问题真的很简单,您正试图在当前呈现的 UIAlertController 上显示另一个 UIAlertController

So, how to solve such a case?

  1. 您需要获取您在当前 View Controller 中使用的所有 UIAlertController 的列表。

  2. 您必须检查在当前 View Controller (或其他 View Controller ,如果您正在执行异步请求)中显示警报的逻辑。

  3. 当您想要在另一个之上显示一个警报时,您的代码必须像这样。

假设 loadingAlert 当前显示在屏幕上:

self.loadingAlert.dismiss(animated: true, completion: {
     let anotherAlert = UIAlertController(title: "New One", message: "The Previous one is dismissed", preferredStyle: .alert)
     let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
     anotherAlert.addAction(okAction)
     self.present(anotherAlert, animated: true, completion: nil)
})

在下一个出现之前,您必须关闭第一个。我做出这个回答是为了消除没有按钮的警报,以提高效率。

So, what about the alert with action buttons?

It will dismiss automatically when you click one of the action buttons on UIAlertController that you created.

但是,如果同时显示两个包含 UIButtonUIAlertController,问题仍然会发生。您需要重新检查每个逻辑,或者您可以在每个操作的处理程序中处理它:

self.connectionErrorAlert.dismiss(animated: true, completion: {
     let anotherAlert = UIAlertController(title: "New One", message: "The Previous one is dismissed", preferredStyle: .alert)
     let okAction = UIAlertAction(title: "OK", style: .default, handler: {action in
            let nextAlert = UIAlertController(title: "New One", message: "The Previous one is dismissed", preferredStyle: .alert)
            self.present(nextAlert, animated: true, completion: nil)
     })
     anotherAlert.addAction(okAction)
     self.present(anotherAlert, animated: true, completion: nil)
})

Mike 的回答:

DispatchQueue.main.async(execute: {

      if self.presentedViewController == nil {
           print("Alert comes up with the intended ViewController")
           var inputTextField = UITextField()

           let textPrompt = UIAlertController(title: "Test", message: "Testing", preferredStyle: .alert)

           textPrompt.addAction(UIAlertAction(title: "Continue", style: .default, handler: {
               (action) -> Void in
               // if the input matches the required text

               let str = inputTextField.text
               if str == requireTextInput {
                    print("right")
               } else {
                    print("wrong")
               }

           }))

           textPrompt.addTextField(configurationHandler: {(textField: UITextField!) in
                textField.placeholder = ""
                inputTextField = textField

            })
            weakSelf?.present(textPrompt, animated: true, completion: nil)
      } else {
            // either the Alert is already presented, or any other view controller
            // is active (e.g. a PopOver)
            // ...
            let thePresentedVC : UIViewController? = self.presentedViewController as UIViewController?
            if thePresentedVC != nil {
                 if let _ : UIAlertController = thePresentedVC as? UIAlertController {
                      print("Alert not necessary, already on the screen !")

              } else {

                      print("Alert comes up via another presented VC, e.g. a PopOver")
              }
            }
       }
})

感谢@Luke 回答:https://stackoverflow.com/a/30741496/3378606

关于ios - 尝试在已经呈现的 View Controller 上呈现 UIAlertController(空)[Swift],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41326654/

相关文章:

ios - -[AVMvidFrameDecoder advanceToFrame :] 'framebuffer num bytes' 中的 AVAnimator 断言失败

swift - '...' 的重载存在这些结果类型 : ClosedRange<Bound>, CountableClosedRange<Bound>

function - SWIFT - 辅助类回调

ios - 打开应用程序 3 次后显示 uialertview?

ios - 当项目具有动态大小时,如何在 Collection View 中有单个水平行的项目?

ios - 使用 xcodebuild 在模拟器上构建并运行应用程序

ios - 拉动以刷新崩溃应用程序,因为索引超出范围

ios - 使用 SKLabel 文本裁剪 SKTexture

ios - 如何制作多行、左对齐的 UIAlertView?

从锁定屏幕接听电话时,iOS 麦克风无法正常工作或无法通过 webrtc 发送语音