如何在视图控制器被关闭后显示警报

How to present an alert after view controller has been dismissed

我有一个应用,用户在后台上传文件通常需要几秒钟。当他们点击 "Done" 按钮并且同时关闭视图控制器时,上传开始。我希望发生的是下载完成后出现警报。我以为我只是将下面的代码添加到上传功能,但它不起作用。我怎样才能出现一个警告框来确认上传成功?

@IBAction func tapDone(_ sender: Any) {
    self.dismiss(animated: true, completion: nil)
    if let image = newImage {
        submit2Parse(image: image)
    }
}

func submit2Parse (image: UIImage) {
    if let pfImage = image2PFFile(image: image) {
        // Insert PFFile into parse server
        let submittedImage = PFObject(className: "Images")
        submittedImage["imageFile"] = pfImage
        submittedImage["type"] = "submittedFromUserHome"
        submittedImage["bride"] = brideSwitch.isOn
        submittedImage["groom"] = groomSwitch.isOn
        submittedImage["user"] = userSwitch.isOn
        submittedImage["picturePeriod"] = pickerSelected
        submittedImage["uploadedByUserId"] = PFUser.current()?.objectId ?? ""            submittedImage["uploadedByUserName"] = PFUser.current()?.username ?? ""
        if !txtIsPlaceHolder { submittedImage["description"] = imageDescription.text }

        submittedImage.saveInBackground { (success, error) in
            if success {
                let message = "Save in bg worked"
                print(message)
                let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
                alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: {
                    (action) in
                    self.dismiss(animated: true, completion: nil)
                }))
                self.present(alert,animated: true, completion: nil)

            } else {
                print(error?.localizedDescription ?? "")
            }
        }
    }
}

代码给出了这个构建错误:

Implicit use of 'self' in closure; use 'self.' to make capture semantics explicit

在你的tapDone方法中,你需要使用completion关闭你的控制器,像这样:

self.dismiss(animated: true) {
    if let image = newImage {
        self.submit2Parse(image: image)
    }
}

这仅意味着 self.submit2Parse(image: image) 将仅在您关闭控制器后执行。此外,错误

Implicit use of 'self' in closure; use 'self.' to make capture semantics explicit

only 意味着您需要使用 self. 在闭包中显式调用变量或方法。所以你的 submit2Parse... 现在应该是这样的:

self.submit2Parse(image: image).

如果我对你的问题的理解正确,你想在用户点击 tapDone 按钮时关闭你的 SecondViewController。之后,一旦您的图片上传完成,您就会想要显示成功警报。

但是如果你 dismiss 它一旦点击按钮你将不会收到任何警报,因为你的 SecondViewController 不再在 window hierarchy 中,如果你尝试显示警报你将在控制台中收到如下错误:

Attempt to present on whose view is not in the window hierarchy!

要解决这个问题,您需要在您关闭第二个视图控制器后显示第一个视图控制器的警报,您可以使用 delegate.

来实现

考虑以下示例:

首先在你的 FirstViewController 之外声明一个 protocol:

protocol UplaodSuccessDelegate:class {
    func uploadSuccess(message: String)
}

然后确认您的代理人相同 class:

class ViewController: FirstViewController, UplaodSuccessDelegate {

那么在present的时候需要通过delegate SecondViewController:

let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
vc.delegate = self. //Pass delegate
self.present(vc, animated: true, completion: nil)

并将委托方法添加到相同的 class:

func uploadSuccess(message: String) {

    let message = "Save in bg worked"
    print(message)
    let alert = UIAlertController(title: "title", message: message, preferredStyle: UIAlertController.Style.alert)
    alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: {
        (action) in

    }))
    self.present(alert,animated: true, completion: nil)
}

现在在您的 SecondViewController 中您需要添加

weak var delegate: UplaodSuccessDelegate?

并在您的 tapDone 方法中将代码替换为:

self.dismiss(animated: true) {
    if let image = newImage {
        submit2Parse(image: image)
    }
}

上传完成后,您需要调用委托方法(上传完成后),例如:

self.delegate?.uploadSuccess(message: "your message")

这将从 FirstViewController.

调用您的委托方法

当你将下面的函数放到viewController中,在后台启动数据上传,然后在提交完成时触发的闭包中调用这个函数,它甚至能够成功创建一个警报认为最初的视图控制器被解雇了(如果是长时间上传,则被解雇了很长时间)。

// This is the function that performs my background upload
    func submit2Parse (image: UIImage) {
        if let pfImage = image2PFFile(image: image) {
            // Insert PFFile into parse server
            let submittedImage = PFObject(className: "Images")
            submittedImage["imageFile"] = pfImage
            submittedImage["imageCreateDt"] = newImageCreateDate
            submittedImage["type"] = "submittedFromUserHome"
            submittedImage["bride"] = brideSwitch.isOn
            submittedImage["groom"] = groomSwitch.isOn
            submittedImage["user"] = userSwitch.isOn
            submittedImage["picturePeriod"] = pickerSelected
            submittedImage["uploadedByUserId"] = PFUser.current()?.objectId ?? ""
            submittedImage["uploadedByUserName"] = PFUser.current()?.username ?? ""
            if !txtIsPlaceHolder { submittedImage["description"] = imageDescription.text }
            // Get the image timestamp, every photo has one
            // How do you get the thumbnail image too?

            submittedImage.saveInBackground { (success, error) in
                if success {
                    let message = "Save in bg worked"
                    print(message)
                    self.showAlertFromAppDelegates()
                } else {
                    print(error?.localizedDescription ?? "")
                }
            }
        }
    }

// This is the function that creates the alert
    func showAlertFromAppDelegates(){
        var topWindow: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
        topWindow?.rootViewController = UIViewController()
        topWindow?.windowLevel = UIWindow.Level.alert + 1
        let alert: UIAlertController =  UIAlertController(title: "Upload Complete", message: "Your image was successfully submitted!", preferredStyle: .alert)
        alert.addAction(UIAlertAction.init(title: "OK", style: .default, handler: { (alertAction) in
            topWindow?.isHidden = true
            topWindow = nil
        }))
        topWindow?.makeKeyAndVisible()
        topWindow?.rootViewController?.present(alert, animated: true, completion:nil)
    }