NSNotification:尝试在ViewController上呈现UIAlertController,其视图不在窗口层次结构中

时间:2016-03-19 18:52:46

标签: ios swift uiviewcontroller uialertcontroller nsnotification

我正在尝试在我的ViewController中显示一个通过NSNotification调用的函数中的UIAlertController。但是我收到了错误:

Attempt to present <UIAlertController: 0x7fe013d05d40> on <submarine.ViewController: 0x7fe011f20370> whose view is not in the window hierarchy!

NSNotification是从我的UI中的其他内容中的完成块(我猜回调)发布的。因为这是一个回调,它无法显示。因此,我认为我会尝试使用NSNotificationCentre来解决问题而不使用rootViewController来显示警报。

我的代码是:

override func viewDidAppear(animated: Bool) {
    // Handle onboarding
    if needsOnboarding() {
        handleOnboarding() // This create the completion block that posts the NSNotification
    }

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "showTermsAlert:", name:"showTermsAlert", object: nil)
}

func showTermsAlert(notification: NSNotification) {
    let termsAlert:UIAlertController = UIAlertController(title: "Terms And Conditions", message: "Please view the terms below before accepting them.", preferredStyle: UIAlertControllerStyle.Alert)

    termsAlert.addAction(UIAlertAction(title: "View Terms", style: .Default, handler: { (action: UIAlertAction!) in
        UIApplication.sharedApplication().openURL(NSURL(string: "my_terms_url")!)
    }))

    termsAlert.addAction(UIAlertAction(title: "I Agree to the Terms", style: .Default, handler: { (action: UIAlertAction!) in
        self.onboardingFinished()
    }))

    self.presentViewController(termsAlert, animated: true, completion: nil)
}

有谁知道为什么会这样?我不明白为什么它不在窗口层次结构中 - 它是从self viewController呈现的,并且是在VC内部的顶级函数中创建的。

谢谢!

编辑:handleOnboarding()中的原始代码:

使用的图书馆:Onboard

func handleOnboarding() {

        let secondPage = OnboardingContentViewController(title: "What's going on?", body: "Submarine routes your data through our network, around any filters and restrictions, giving you unrestricted and unmonitored internet access.", image: UIImage(named: "back"), buttonText: "Next") { () -> Void in
            // do something here when users press the button, like ask for location services permissions, register for push notifications, connect to social media, or finish the onboarding process
        }
        secondPage.movesToNextViewController = true

        let thirdPage = OnboardingContentViewController(title: "Terms of Use", body: "You must agree to our Terms of Use to use Submarine.\nIf you don't, please close Submarine.", image: UIImage(named: "back"), buttonText: "View Terms") { () -> Void in

            let termsAlert:UIAlertController = UIAlertController(title: "Terms And Conditions", message: "Please view the terms below before accepting them.", preferredStyle: UIAlertControllerStyle.Alert)

            termsAlert.addAction(UIAlertAction(title: "View Terms", style: .Default, handler: { (action: UIAlertAction!) in
                UIApplication.sharedApplication().openURL(NSURL(string: "my_policy_url")!)
            }))

            termsAlert.addAction(UIAlertAction(title: "I Agree to the Terms", style: .Default, handler: { (action: UIAlertAction!) in
                self.onboardingFinished()
            }))

            self.presentViewController(termsAlert, animated: true, completion: nil)

//            NSNotificationCenter.defaultCenter().postNotificationName("showTermsAlert", object: nil)
        }

        // Image
        let onboardingVC = OnboardingViewController(backgroundImage: UIImage(named: "back"), contents: [secondPage, thirdPage])

        self.navigationController?.presentViewController(onboardingVC, animated: false, completion: nil)

    }

2 个答案:

答案 0 :(得分:2)

当呈现视图控制器不再是控制器层次结构的一部分时,会发生这种情况,并且它的视图不再位于任何窗口的视图层次结构中。最有可能的是,控制器被解雇或弹出,但它听到了通知并试图出示警报控制器。

您应该更仔细地管理控制器状态。当控制器被解除或从控制器层次结构中弹出时,可能会删除观察者。

答案 1 :(得分:0)

我的代码中有一些我要改变的东西。在viewDidAppear:中添加对超级电话的呼叫,并停止使用NSNotification进行演示。您不知道使用此模式将调用哪个线程showTermsAlert。您可以通过直接调用showTermsAlert来更明确地表达您的意图,这也可以保证您在主线程上。

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    // Handle onboarding
    if needsOnboarding() {
        self.showTermsAlert()
    }
}

func showTermsAlert() {
    let termsAlert:UIAlertController = UIAlertController(title: "Terms And Conditions", message: "Please view the terms below before accepting them.", preferredStyle: UIAlertControllerStyle.Alert)

    termsAlert.addAction(UIAlertAction(title: "View Terms", style: .Default, handler: { (action: UIAlertAction!) in
    UIApplication.sharedApplication().openURL(NSURL(string: "my_terms_url")!)
}))

    termsAlert.addAction(UIAlertAction(title: "I Agree to the Terms", style: .Default, handler: { (action: UIAlertAction!) in
    self.onboardingFinished()
}))

    self.presentViewController(termsAlert, animated: true, completion: nil)
}