Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/96.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 尝试在已呈现的视图控制器上呈现UIAlertController(null)[Swift]_Ios_Swift_Uialertview_Uialertcontroller - Fatal编程技术网

Ios 尝试在已呈现的视图控制器上呈现UIAlertController(null)[Swift]

Ios 尝试在已呈现的视图控制器上呈现UIAlertController(null)[Swift],ios,swift,uialertview,uialertcontroller,Ios,Swift,Uialertview,Uialertcontroller,我有一个警报视图,我正试图在照片视图中显示 照片显示在列表中,可以推送到全屏视图 正在以编程方式显示照片视图。我认为这就是问题的原因,因为警报视图试图在已经呈现的(照片)视图之上呈现另一个视图 警报视图正试图显示,但出现以下错误: Warning: Attempt to present <UIAlertController: 0x147d2c6b0> on <LiveDeadApp.ListViewController: 0x147d614c0> which is al

我有一个警报视图,我正试图在照片视图中显示

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

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

警报视图正试图显示,但出现以下错误:

Warning: Attempt to present <UIAlertController: 0x147d2c6b0>  on <LiveDeadApp.ListViewController: 0x147d614c0> which is already presenting (null)
<pre><code>    
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *btn1;
@property (weak, nonatomic) IBOutlet UIButton *btn2;
@end

@implementation ViewController

- (void)viewDidLoad {
   [super viewDidLoad];
}

- (IBAction)btn1:(id)sender {
   UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Btn1"
                   message:@"This is Btn1." preferredStyle:UIAlertControllerStyleAlert];

   UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}];

   [alert addAction:defaultAction];
   [self presentViewController:alert animated:YES completion:nil];
}

- (IBAction)btn2:(id)sender {
   UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Btn2"
                     message:@"This is Btn2." preferredStyle:UIAlertControllerStyleAlert];

   UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}];

   [alert addAction:defaultAction];
   [self presentViewController:alert animated:YES completion:nil];
}
</code></pre>
这是主列表视图

这是拍摄屏幕截图时的主列表视图

这是主要的照片视图

这是主照片视图中的弹出框(通过“i”按钮访问)

在主照片视图上拍摄屏幕截图时,不会出现警告视图。但是,当设备的方向改变时,照片视图返回列表并显示警报。

这就是我要做的:

iOS 10中的Swift 3

谢谢大家!

以下是列表视图和照片视图的代码:

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
}
}
在ViewDidLoad中,
使
变量,如
弱var weakSelf=self


在通知中心,
呈现
textPropmt
类似

weak var weakSelf = self
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationUserDidTakeScreenshot, object: nil, queue: OperationQueue.main, using:
        { notification in
 DispatchQueue.main.async(execute: {
  //create textPrompt here in Main Thread
  weakSelf.present(textPrompt, animated: true, completion: nil)
 })
})

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

那么,如何解决这种情况呢

  • 您需要获取当前视图控制器中使用的所有
    UIAlertController
    的列表。

  • 您必须检查当前视图控制器(或其他视图控制器,如果您正在执行异步请求)中显示警报的逻辑。

  • 如果要在一个警报上显示另一个警报,则代码必须如下所示。

  • 假设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)
    })
    
    在下一个出现之前,您必须先关闭第一个。我之所以这样回答是因为我拒绝了一个没有按钮的警报,以提高它的效率

    那么,带操作按钮的警报呢?

    当您单击其中一个操作时,它将自动关闭 您创建的
    UIAlertController
    上的按钮

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

    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)
    })
    
    要回答迈克的问题

    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 Answer:

    在我的情况下,我无法将我的放在类重写中。下面是我得到的:

    let viewController = self // I had viewController passed in as a function,
                              // but otherwise you can do this
    
    
    // Present the view controller
    let currentViewController = UIApplication.shared.keyWindow?.rootViewController
    currentViewController?.dismiss(animated: true, completion: nil)
    
    if viewController.presentedViewController == nil {
        currentViewController?.present(alert, animated: true, completion: nil)
    } else {
        viewController.present(alert, animated: true, completion: nil)
    }
    

    我受了这个问题的折磨,一直到现在。这是一个简单的应用程序,上面有两个按钮。点击第一个按钮会导致“2019-03-05 16:58:04.094541-0500 ReadJason[41100:1610082]警告:尝试呈现已呈现的内容”错误

    将按钮2复制为按钮1导致此问题。每个按钮都绑定到一个动作(btn1和btn2)。当我复制btn2来制作btn1时,btn2的连接包含在btn1的代码中。然后,我将连接添加到btn1,这导致两个发送事件连接到btn1,这就是导致错误的原因

    检查按钮1的事件将显示两个操作:。删除不需要的操作将清除错误


    Hy,我尝试了一个更简单的解决方案,似乎有效,并且能够在第一个警报之前显示第二个警报,该警报将保持不变(在用户回答问题之前无需解除警报):


    我相信,您需要确保是否已经有另一个AlerViewController试图在ViewController上表示自己


    至少这是我的问题。

    我是否应该将警报视图的所有代码放在主线程的“//create textPrompt”中?谢谢你的回复!这就是为什么我在代码中添加了该注释,去吧,好的,对不起。仍然得到错误,没有弹出窗口。必须在“weakSelf”之后添加“?”。仅当您尝试呈现已呈现的控制器(或呈现的任何其他控制器)时,才会出现此错误。检查您是否在代码中的某个地方两次显示“UIAlertController”。@KrishnaDattShukla这是我唯一显示警报控制器的地方。不过,我也在演示一个popover控制器。我认为您同时演示了popover和alert。这就是产生此错误的原因。解除popover后,请出示您的警报控制器。@KrishnaDattShukla我不确定如何执行此操作。我已经在我的问题中添加了一些照片以供澄清。非常感谢你!谢谢你的全面回复。我仍然不确定如何着手做这件事。我已经在我的问题中添加了一些照片以供澄清。非常感谢。您当前的问题中有多少控制器?只有一个listViewController?只有一个:listViewController。如果我没记错的话,您正在listViewController中显示照片(1,2,3)。单击其中一个按钮时,将显示详细信息(假设1)。当您单击信息(i)时,弹出窗口会出现,当您单击“添加到Fav”时,会出现警报。我说的对吗?除了“添加到Fav”部分外,这是正确的。“添加到Fav”与此问题是分开的。拍摄屏幕截图时会出现此警报。这是一个优雅的简单解决方案,但您最好检查presentedViewController!=事先通知视图控制器。
    <pre><code>    
    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UIButton *btn1;
    @property (weak, nonatomic) IBOutlet UIButton *btn2;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
       [super viewDidLoad];
    }
    
    - (IBAction)btn1:(id)sender {
       UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Btn1"
                       message:@"This is Btn1." preferredStyle:UIAlertControllerStyleAlert];
    
       UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}];
    
       [alert addAction:defaultAction];
       [self presentViewController:alert animated:YES completion:nil];
    }
    
    - (IBAction)btn2:(id)sender {
       UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Btn2"
                         message:@"This is Btn2." preferredStyle:UIAlertControllerStyleAlert];
    
       UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}];
    
       [alert addAction:defaultAction];
       [self presentViewController:alert animated:YES completion:nil];
    }
    </code></pre>
    
    if self.presentedViewController==nil{
        self.present(MyAlert, animated: true, completion: nil)
    }else{
        self.presentedViewController!.present(MyAlert, animated: true, completion: nil)
    }