Reputation:
I am currently calling an Banner Ad from admob with the following code in my GameViewController.
class GameViewController: UIViewController {
var bannerView: GADBannerView!
}
override func viewDidLoad() {
super.viewDidLoad()
bannerView = GADBannerView(adSize: kGADAdSizeBanner)
addBannerViewToView(bannerView)
bannerView.adUnitID = "ca-app-pub-XXXXXXXXX" // Default Google Test Ad Address
bannerView.rootViewController = self
bannerView.load(GADRequest())
bannerView.isHidden = false // <----- This works, but doesn't work in GameScene.swift
and this is the function that is called from the code above (also in GameViewController) to display the ad.
func addBannerViewToView(_ bannerView: GADBannerView) {
bannerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(bannerView)
view.addConstraints(
[NSLayoutConstraint(item: bannerView,
attribute: .bottom,
relatedBy: .equal,
toItem: bottomLayoutGuide,
attribute: .top,
multiplier: 1,
constant: 0),
NSLayoutConstraint(item: bannerView,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant: 0)
])
}
This code works and displays the test ad. However, in GameScene.swift when I press a button I run this code to try hide the ad.
GameViewController().bannerView.isHidden = true
This causes the app to crash with "Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value". And if I change it, it won't crash, but the ad won't hide.
GameViewController().bannerView?.isHidden = true
Yet in GameViewController, if I simply change the value of isHidden to true, then it works.
bannerView.isHidden = true
Anyway to be able to hide the banner ad from the GameScene.swift when I press the button?
Upvotes: 1
Views: 319
Reputation: 564
When you are calling GameViewController()
you are creating a new instance of GameViewController
.
On GameViewController().bannerView
you are accessing the bannerView
from this new instance, and since it's an optional value which was not set on this instance, when you try to access it - will result in a crash.
What you need is to have access the main GameViewController
, where you had the bannerView
set.
There are two simple methods to call GameViewController
functions from other classes: through a delegate
or by making the class instance static
.
// DELEGATE
//
// You have access only to the functions you declared inside the procotol.
// Only the classes that conforms to that protocol have access to the functions.
//
// GameViewController.swift
protocol GameView_Delegate
{
func hide_ads()
}
class GameViewController: UIViewController, GameView_Delegate
{
override func viewDidLoad()
{
// ...
if let view = self.view as! SKView?
{
if let scene = SKScene(fileNamed: "GameScene")
{
scene.scaleMode = .aspectFill
// pass protocol reference
scene.gv_delegate = self
}
view.presentScene(scene)
}
// ...
}
func hide_ads()
{
// hide ads code
bannerView.isHidden = true
}
}
// GameScene.swift
class GameScene: SKScene
{
var gv_delegate : GameView_Delegate!
func settings()
{
// call function hide_ads from GameViewController
gv_delegate.hide_ads()
}
func lost_scene()
{
let transition = SKTransition.fade(with: UIColor.white, duration: 1.0)
let next_scene = LostScene()
next_scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
next_scene.scaleMode = self.scaleMode
next_scene.size = self.size
// before moving to next scene, we must pass the delegate, so we
// don't lose the connection with the GameViewController
next_scene.gv_delegate = gv_delegate
self.view?.presentScene(next_scene, transition: transition)
}
}
// LostScene.swift
class LostScene: SKScene
{
var gv_delegate : GameView_Delegate!
func settings()
{
// call function hide_ads from GameViewController
gv_delegate.hide_ads()
}
func game_scene()
{
let transition = SKTransition.fade(with: UIColor.white, duration: 1.0)
let next_scene = GameScene()
next_scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
next_scene.scaleMode = self.scaleMode
next_scene.size = self.size
// before moving to next scene, we must pass the delegate, so we
// don't lose the connection with the GameViewController
next_scene.gv_delegate = gv_delegate
self.view?.presentScene(next_scene, transition: transition)
}
}
When you enter a new scene, for example LostScene
, the old scene GameScene
in our case is deallocated (all variables emptied, all references destroyed) and a new GameScene
instance is created and displayed on screen. Before transitioning to the new scene, you should pass the reference so you don't lose the connection with the GameViewController
(as in my example).
// STATIC
//
// the properties and functions are available from everywhere
//
// GameViewController.swift
class GameViewController: UIViewController
{
static var shared : GameViewController!
override func viewDidLoad()
{
super.viewDidLoad()
GameViewController.shared = self
// ...
}
func hide_ads()
{
// hide ads code
bannerView.isHidden = true
}
}
// GameScene.swift
class GameScene: SKScene
{
func settings()
{
// call function hide_ads from GameViewController
GameViewController.shared.hide_ads()
// or GameViewController.shared.bannerView.isHidden = true
}
}
Upvotes: 0
Reputation:
If anyone is wondering, this is the solution I found to hide the banner:
"Handle all the banner stuff in the GameViewController.swift file. Inside there, assign a tag value for the bannerView variable. Then when the scene loads, load the bannerView using the tag id, then set its .isHidden property to true"
GameViewController.swift
bannerView.tag = 100
GameScene.swift
// hide banner
let bannerView = self.view?.viewWithTag(100) as! GADBannerView?
bannerView?.isHidden = true
// show banner
let bannerView = self.view?.viewWithTag(100) as! GADBannerView?
bannerView?.isHidden = false
Upvotes: 0
Reputation: 16381
You're creating a new instance of GameViewController
and toggling it's bannerView
's isHidden
property. You should toggle the isHidden
property of the bannerView
of GameViewController
instance that you're displaying.
Upvotes: 2