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
相关产品推荐
相关产品推荐

