GADInterstitial presentFromRootViewController:应用从后台退出后导致崩溃

GADInterstitial presentFromRootViewController: causes crash after app resigns from background

我在显示来自 admobs 的 GADInterstitial 后遇到问题。

我做的是:

  1. 使用 presentFromRoot 打开 GADInterstitialViewController:
  2. 关闭它并将应用程序置于后台
  3. 等几分钟
  4. 再次打开应用程序
  5. 单击 UI 元素

现在应用程序崩溃并出现 SIGSEGV 错误,原因是

objc_msgSend() selector name: _setContentMargin:

。看来我的记忆有些问题,而且是新整理的什么的。它接缝现在有一个新对象并且它没有选择器的响应者。但它只会在我打开 GADInterstitial 一次后发生。如果我没有打开 GADInterstitial,它运行没有问题。

我像示例中的 google 一样加载并显示插页式广告...我不知道发生了什么...

我有一个全局 UIViewController 决定是否显示广告。如果不是,它会将 contenViewController 直接包装为 ChildViewController。如果它必须显示广告,它的 childviewController 将是一个 "AdViewContoller"。然后,这会将内容包装为 ChildViewController:

所以我有以下结构:

这是我的广告ViewController:

import UIKit
import GoogleMobileAds

let kAD_UNIT_ID_BANNER_AD: String = "ca-app-pub-3940256099942544/2934735716"
let kAD_UNIT_ID_INTERSTITIAL_AD: String = "ca-app-pub-3940256099942544/4411468910"

let kVIEW_CONTROLLER_ALLOWS_TO_SHOW_INTERSTITIAL_NOTIFICATION: String = "kviewcontrollerallowstoshowinterstitialnotification"

class AdViewController: UIViewController, GADBannerViewDelegate {


    var childController: UIViewController? {
        didSet {
            if self.childController != nil {
                self.addChildViewController(self.childController!)
            }
        }
    }
    var contentView: UIView = UIView()
    var adLayoutConstraint: NSLayoutConstraint?

    let adView: UIView = UIView();
    let gadAdView: GADBannerView = GADBannerView(adSize: kGADAdSizeSmartBannerPortrait)
    var intAdView: GADInterstitial?

    override func viewDidLoad() {
        super.viewDidLoad()

        if self.childController != nil {
            self.view.addSubview(self.childController!.view)
            self.contentView = self.childController!.view
            self.contentView.translatesAutoresizingMaskIntoConstraints = false
        }

        self.view.addSubview(self.adView)
        self.adView.translatesAutoresizingMaskIntoConstraints = false
        self.adView.backgroundColor = UIColor.blackColor()

        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[content]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["content":self.contentView]))
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[ad]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["ad":self.adView]))
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[content][ad]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["ad":self.adView, "content":self.contentView]))
        self.adLayoutConstraint = NSLayoutConstraint(item: self.adView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 50
        )
        self.adView.addConstraint(self.adLayoutConstraint!)

        self.adView.addSubview(self.gadAdView)
        self.gadAdView.translatesAutoresizingMaskIntoConstraints = false
        self.adView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[gad]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["gad":self.gadAdView]))
        self.adView.addConstraint(NSLayoutConstraint(item: self.gadAdView, attribute: .CenterX, relatedBy: .Equal, toItem: self.adView, attribute: .CenterX, multiplier: 1, constant: 0))
        //self.adView.addConstraint(NSLayoutConstraint(item: self.gadAdView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 320))

        gadAdView.adUnitID = kAD_UNIT_ID_BANNER_AD
        gadAdView.rootViewController = self
        gadAdView.loadRequest(GADRequest())
        gadAdView.delegate = self

        self.hideBanner()


        NSNotificationCenter.defaultCenter().addObserver(self, selector: "askedForInterstitial:", name: kVIEW_CONTROLLER_ALLOWS_TO_SHOW_INTERSTITIAL_NOTIFICATION, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "initInterstitial", name: UIApplicationDidBecomeActiveNotification, object: nil)

        // Do any additional setup after loading the view.
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
    }

    func hideBanner() -> Void {
        self.adLayoutConstraint?.constant = 0
        self.view.layoutIfNeeded()
    }
    func showBanner() -> Void {
        self.adLayoutConstraint?.constant = 50
        self.view.layoutIfNeeded()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func initInterstitial() -> Void {
        print("UIApplicationDidBecomeActiveNotification called!")
        self.intAdView = GADInterstitial(adUnitID: kAD_UNIT_ID_INTERSTITIAL_AD)
        let request = GADRequest()
        self.intAdView?.loadRequest(request)
    }


    init(subController: UIViewController) {
        super.init(nibName: nil, bundle: nil)
        self.childController = subController
        self.addChildViewController(self.childController!)
    }


    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func adViewDidReceiveAd(bannerView: GADBannerView!) {
        self.showBanner()
    }
    func adView(bannerView: GADBannerView!, didFailToReceiveAdWithError error: GADRequestError!) {
        self.hideBanner()
    }

    func askedForInterstitial(notification:NSNotification) -> Void {
        if notification.userInfo != nil {
            if let c = notification.userInfo!["controller"] as? UIViewController {
                self.showInterstitialInController(c)
            } else {
                self.showInterstitialInController(self)
            }
        } else {
            self.showInterstitialInController(self)
        }
    }

    class func presentInterstitial() -> Void {
        AdViewController.presentInterstitialInController(nil)
    }

    class func presentInterstitialInController(c: UIViewController?) {
        if c == nil {
            NSNotificationCenter.defaultCenter().postNotificationName(kVIEW_CONTROLLER_ALLOWS_TO_SHOW_INTERSTITIAL_NOTIFICATION, object: nil)
        }
        else {
            NSNotificationCenter.defaultCenter().postNotificationName(kVIEW_CONTROLLER_ALLOWS_TO_SHOW_INTERSTITIAL_NOTIFICATION, object: nil, userInfo: ["controller": c!])
        }
    }

    private func showInterstitialInController(c: UIViewController) -> Void {
        if self.intAdView != nil && self.intAdView!.isReady {
            self.intAdView!.presentFromRootViewController(c)
        }
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

这个控制器也有横幅。但当我试图向您展示我的整个过程时,我认为您也必须看到这一点。 我有这两个 class 函数 presentInterstitialpresentInterstitialInController ,层次结构中的所有子视图控制器都可以要求显示插页式广告。这很好用,但正如我所说,问题接缝发生在应用程序处于后台后。

感谢您的帮助

亚瑟

好的,我已经解决了...

问题不是插页式广告,而是我为 UIApplicationDidBecomeActiveNotification 通知名称添加观察者的行:

我有一个功能:

func initInterstitial() -> Void {
    print("UIApplicationDidBecomeActiveNotification called!")
    self.intAdView = GADInterstitial(adUnitID: kAD_UNIT_ID_INTERSTITIAL_AD)
    let request = GADRequest()
    self.intAdView?.loadRequest(request)
}

这个函数我添加为

的观察者
NSNotificationCenter.defaultCenter().addObserver(self, selector: "initInterstitial", name: UIApplicationDidBecomeActiveNotification, object: nil)

第二次调用 Notification 后我的应用程序没有崩溃。

现在,如果我将函数重命名为 createInterstital:

func createInterstitial() -> Void {
    print("UIApplicationDidBecomeActiveNotification called!")
    self.intAdView = GADInterstitial(adUnitID: kAD_UNIT_ID_INTERSTITIAL_AD)
    let request = GADRequest()
    self.intAdView?.loadRequest(request)
}

然后我这样添加观察者:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "createInterstitial", name: UIApplicationDidBecomeActiveNotification, object: nil)

所有作品都很完美...

我不知道为什么,但 NotificationCenter 似乎不喜欢其中包含 init 的函数。

希望这对某些人有所帮助。

问候

阿图尔