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

Swift:如何从AdMob监听类调用SKScene中的方法?

解决AdMob奖励广告代理方法不触发的问题(实例存活问题)

看起来你已经找对了代理的实现思路,问题核心确实是实例的生命周期管理——你的Ads_Rewarded_Support实例没有被GameScene强持有,当AdMob的异步回调(比如didRewardUserWith)触发时,这个广告管理实例已经被ARC自动释放了,代理方法自然无法被调用。

下面是具体的修复步骤:

1. 确保GameScene强持有广告管理实例,并正确设置代理

你当前的代码里,rewardedAd是用let声明的强引用属性,这没问题,但不能直接在类定义的顶级作用域设置代理(因为此时self还未完全初始化)。需要把代理设置放在合适的生命周期方法里,比如didMove(to view:):

class GameScene: SKScene, Ads_Rewarded_SupportDelegate {
    // 用强引用(let/var)持有广告管理实例,避免被提前释放
    private let rewardedAd = Ads_Rewarded_Support()
    
    override func didMove(to view: SKView) {
        super.didMove(to: view)
        // 在这里设置代理,确保self已经完成初始化
        rewardedAd.delegate = self
    }
    
    func rewardedFinishSuccessfuly() {
        print("rewarded Finish Successfuly")
    }
    
    func rewardedAdClosed() {
        print("Rewarded ad closed")
    }
    
    // 示例:触发广告展示的方法
    func triggerRewardedAd() {
        rewardedAd.loadAndShowAd() // 替换成你实际的广告展示方法
    }
}

2. 确保Ads_Rewarded_Support内部强持有广告实例

除了广告管理类本身要被持有,它内部的AdMob广告实例(比如GADRewardBasedVideoAd)也需要被强引用,否则同样会被提前释放:

protocol Ads_Rewarded_SupportDelegate: class {
    func rewardedFinishSuccessfuly()
    func rewardedAdClosed()
}

class Ads_Rewarded_Support: NSObject, GADRewardBasedVideoAdDelegate {
    weak var delegate: Ads_Rewarded_SupportDelegate?
    // 强持有AdMob广告实例,保证其生命周期覆盖广告的异步流程
    private var rewardedAd: GADRewardBasedVideoAd?
    
    override init() {
        super.init()
        // 初始化广告实例并设置自身为代理
        rewardedAd = GADRewardBasedVideoAd.sharedInstance()
        rewardedAd?.delegate = self
    }
    
    // 示例:加载并展示广告的方法
    func loadAndShowAd() {
        let adRequest = GADRequest()
        // 替换成你的广告单元ID
        rewardedAd?.load(adRequest, withAdUnitID: "ca-app-pub-xxx/xxx")
    }
    
    // AdMob回调:广告加载完成,这里可以触发展示
    func rewardBasedVideoAdDidReceiveAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
        // 确保当前有可用的视图控制器来展示广告
        if let rootVC = UIApplication.shared.keyWindow?.rootViewController {
            rewardBasedVideoAd.present(fromRootViewController: rootVC)
        }
    }
    
    // AdMob回调:用户获得奖励
    func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd, didRewardUserWith reward: GADAdReward) {
        // 调用代理方法通知GameScene
        delegate?.rewardedFinishSuccessfuly()
    }
    
    // AdMob回调:广告关闭
    func rewardBasedVideoAdDidClose(_ rewardBasedVideoAd: GADRewardBasedVideoAd) {
        delegate?.rewardedAdClosed()
    }
}

关键原因说明

  • ARC(自动引用计数)会在对象没有强引用时自动释放它。广告加载、用户观看都是异步操作,需要广告管理实例和广告实例在整个流程中保持存活,直到所有回调完成。
  • weak var delegate的用法是正确的(避免GameScene和Ads_Rewarded_Support之间的循环引用),但必须保证持有方(GameScene)对广告管理实例是强引用。

额外排查点

  • 确认广告单元ID正确,且测试设备已添加到AdMob后台的测试设备列表(避免因广告加载失败导致回调不触发)。
  • 可以在Ads_Rewarded_Support的所有AdMob回调方法中添加打印日志,确认广告的生命周期是否正常触发(比如加载成功、展示、奖励、关闭等)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:50:11