Comrod33
Comrod33

Reputation: 161

Admob Banner Ad Becomes Nil When Switching Scenes In SpriteKit

I've been trying to add an Admob banner advertisement to my spritekit game, and although I've been successful in getting the advertisement to show up initially in the first scene of the game (MenuScene), when I leave that scene (to go to GameScene, SettingsScene, etc.) and then return to the menu scene, I get the error: unexpectedly found nil while unwrapping an Optional value

Basically, whenever I leave MenuScene, the banner ad variable becomes nil, and when I return to it the game bugs out because it's trying to call on a nil value.

I have tried initializing the banner ad in the GameViewController, MenuScene, and SettingsScene (with the methods remaining in GameViewController and just being called in the MenuScene or SettingsScene in the two latter options) - the banner ad always became when leaving the menu scene, and was nil upon arrival in the settings scene.

I suspect that my problem may have something to do with the fact that the GameViewController is only directly related to the MenuScene, and that when the player transitions away from MenuScene (and consequently away also from GameViewController) to another scene, all the variables in GameViewController become nil. However, I have no idea what to do, and would appreciate some help in this regard. Here is my initialization code:

In GameViewController:

var bannerAd: GADBannerView!

func initializeBanner() {
    bannerAd = GADBannerView(adSize: kGADAdSizeSmartBannerLandscape, origin: CGPoint(x: 0, y: self.view.frame.size.height-32))
    bannerAd.isHidden = true
    bannerAd.adUnitID = "ca-app-pub-3940256099942544/2934735716"
    bannerAd.rootViewController = self
    view.addSubview(bannerAd)
}

func requestBanner() {
    let request = GADRequest()
    request.testDevices = ["31340db3ea728bd5faf2789325b27620"]
    bannerAd.load(request)
}

In MenuScene:

var gameVC: GameViewController!

override func didMove(to view: SKView) {
    gameVC.initializeBanner()
    gameVC.requestBanner()
    gameVC.bannerAd.isHidden = false
}

When transitioning to (for example) SettingsScene:

gameVC.bannerAd.isHidden = true

Upvotes: 1

Views: 298

Answers (1)

crashoverride777
crashoverride777

Reputation: 10674

As you mentioned you will loose the reference to your GameViewController when you change scenes. In general its not the best practice to reference the GameViewController in your SKScenes.

A better approach to call the GameViewController method would be using Notification Center or delegation.

Create a key for your notification to avoid typos. You can put this anywhere you like in your project (outside any class or a new .swift file)

 extension Notification.Name {
    static let showBannerAd = Notification.Name(rawValue: "ShowBanner")
 }

Than in your GameViewController add the observer in ViewDidLoad to call the requestBanner method

NotificationCenter.default.addObserver(self, selector: #selector(requestBanner), name: .showBannerAd, object: nil) // selector is the method to call

and than in your SKScene(s) you can post the notification like so when you need to show the banner.

 NotificationCenter.default.postNotificationName(.showBannerAd, object: nil)

How to present ads during certain scenes in sprite-kit?

Also to avoid such crashes you should not force unwrap your properties (!) unless you know 100% that it will not be nil. By writing

 var bannerAd: GADBannerView!

you tell xCode that this banner property will always be there and will never be nil. Thats not the case tho and thus makes your code less solid. So instead you should make it an optional property like this

 var bannerAd: GADBannerView?

and than your setup method like this

  func initializeBanner() {
       bannerAd = GADBannerView(adSize: kGADAdSizeSmartBannerLandscape, origin: CGPoint(x: 0, y: self.view.frame.size.height-32))
       bannerAd?.isHidden = true
       bannerAd?.adUnitID = "ca-app-pub-3940256099942544/2934735716"
       bannerAd?.rootViewController = self
       view.addSubview(bannerAd!)
 }

Now when the banner property is nil you will not crash when for example saying this

 bannerAd?.isHidden = true

Alternatively I have a helper on Github which will make this much easier and cleaner.

https://github.com/crashoverride777/SwiftyAds

Hope this helps

Upvotes: 3

Related Questions