Swift GAD插页广告未准备好崩溃及重复展示异常问题
GAD插页广告问题修复方案
问题1:广告未加载完成触发展示导致崩溃
根因:
CreateAd方法存在无限递归:当interstitial为空时,else分支直接递归调用CreateAd(),但方法内部没有任何广告加载逻辑,interstitial永远不会被赋值,递归会持续到栈空间耗尽,触发栈溢出类型的EXC_BAD_ACCESS错误- 额外问题:
interstitial声明为隐式解包可选类型GADInterstitialAd!,空值时强制访问会直接崩溃;Timer的selector写的是ViewController.CreateAd,如果当前类名是JournalViewController会触发找不到方法的崩溃
问题2:广告关闭后循环展示不生效
根因:
- 广告加载逻辑没有封装复用:你仅在
viewDidLoad中执行了一次广告加载,没有封装独立的加载方法,单次展示后的广告失效后无法生成新的广告实例 CreateAd方法职责错误:该方法没有实现广告加载逻辑,仅做了存在时展示、不存在时递归的错误逻辑,在adDidDismissFullScreenContent中调用也无法生成新广告
修正后的完整实现代码
class JournalViewController: UIViewController, GADFullScreenContentDelegate { // 改为普通可选类型,避免隐式解包崩溃 var interstitial: GADInterstitialAd? // 持有Timer避免提前释放,同时方便销毁 var adTimer: Timer? override func viewDidLoad() { super.viewDidLoad() // 首次加载广告 loadInterstitialAd() // 启动首次展示定时器 resetAdTimer() } // 封装独立的广告加载方法,需要新加载时直接调用 func loadInterstitialAd() { let request = GADRequest() GADInterstitialAd.load( withAdUnitID:"你的广告ID", request: request, completionHandler: { [weak self] ad, error in guard let self = self else { return } if let error = error { print("Failed to load interstitial ad with error: \(error.localizedDescription)") // 加载失败可以选择延迟重试,按需开启 // DispatchQueue.main.asyncAfter(deadline: .now() + 5) { [weak self] in // self?.loadInterstitialAd() // } return } self.interstitial = ad self.interstitial?.fullScreenContentDelegate = self } ) } // 封装定时器重置方法 func resetAdTimer() { // 先销毁旧定时器避免重复触发 adTimer?.invalidate() let randomTime = Double(arc4random() + 20).truncatingRemainder(dividingBy: 60.0) adTimer = Timer.scheduledTimer( timeInterval: randomTime, target: self, selector: #selector(tryPresentInterstitialAd), userInfo: nil, repeats: false ) } // 原CreateAd方法重命名,职责改为仅尝试展示广告 @objc func tryPresentInterstitialAd() { if let interstitial = interstitial { // 广告存在直接展示 interstitial.present(fromRootViewController: self) } else { print("Ad not ready, trigger reload") // 广告未加载完成,先触发加载,下次定时器再尝试展示 loadInterstitialAd() // 直接重置定时器,下次再试 resetAdTimer() } } // 广告关闭回调 func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) { // 展示过的广告直接置空 interstitial = nil // 加载新的广告 loadInterstitialAd() // 重置下一次展示的定时器 resetAdTimer() } // 页面销毁时销毁定时器,避免循环引用 deinit { adTimer?.invalidate() } }
内容的提问来源于stack exchange,提问作者neofliesgtt
相关产品推荐
相关产品推荐

