You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS16下SwiftUI中AdMob插屏广告实现崩溃问题咨询

iOS16下SwiftUI实现AdMob插屏广告崩溃修复方案

问题背景

iOS16环境下用SwiftUI开发AdMob插屏广告时会直接崩溃,iOS15上运行完全正常,崩溃报错如下:

SwiftUI/UIViewControllerRepresentable.swift:332: Fatal error:
UIViewControllerRepresentables must be value types: InterstitialAdView
2022-11-20 15:34:32.811071+0300 MyApp[38437:1156286]
SwiftUI/UIViewControllerRepresentable.swift:332: Fatal error:
UIViewControllerRepresentables must be value types: InterstitialAdView

核心冲突:UIViewControllerRepresentable要求实现者必须是值类型(struct),但NSObject和GADFullScreenContentDelegate只能在类(class)中实现,原代码用class同时实现三个协议,导致iOS16触发类型检查崩溃。

修改方案

把原有的单一class拆成两部分:一个struct负责实现UIViewControllerRepresentable,一个独立class负责处理AdMob的代理回调,既满足SwiftUI的类型要求,又能正常使用AdMob的代理功能。

1. 独立广告代理类

专门处理AdMob全屏广告的回调逻辑,继承NSObject并实现GADFullScreenContentDelegate:

final class InterstitialAdDelegate: NSObject, GADFullScreenContentDelegate {
    private let adUnitId: String
    private let onDismiss: () -> Void
    
    init(adUnitId: String, onDismiss: @escaping () -> Void) {
        self.adUnitId = adUnitId
        self.onDismiss = onDismiss
        super.init()
    }
    
    // 广告关闭后的回调
    func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        // 加载下一条广告,为下次展示做准备
        InterstitialAd.shared.loadAd(withAdUnitId: adUnitId)
        // 通知SwiftUI关闭广告视图
        onDismiss()
    }
}

2. SwiftUI广告视图struct

实现UIViewControllerRepresentable协议,负责创建视图控制器并展示广告:

struct InterstitialAdView: UIViewControllerRepresentable {
    @Binding var isPresented: Bool
    let adUnitId: String
    
    func makeUIViewController(context: Context) -> UIViewController {
        let viewController = UIViewController()
        // 延迟1毫秒展示,确保广告已加载完成
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1)) {
            showAd(from: viewController)
        }
        return viewController
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
    
    private func showAd(from root: UIViewController) {
        guard let ad = InterstitialAd.shared.interstitialAd else {
            // 广告未加载成功,直接关闭视图
            isPresented.toggle()
            return
        }
        // 创建代理实例,绑定关闭回调
        let delegate = InterstitialAdDelegate(adUnitId: adUnitId) { [weak self] in
            self?.isPresented.toggle()
        }
        ad.fullScreenContentDelegate = delegate
        ad.present(fromRootViewController: root)
    }
}

修改思路说明

  • 拆分职责:把UIViewControllerRepresentable的实现(值类型要求)和AdMob代理逻辑(类类型要求)分开,规避类型冲突。
  • 闭包传值:代理类通过闭包将广告关闭事件传递给SwiftUI视图,更新绑定的isPresented状态。
  • 避免内存泄漏:闭包中使用[weak self]防止循环引用,确保视图销毁时相关资源能正常释放。

内容的提问来源于stack exchange,提问作者Aleksei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 07:40:32