swift: How to call an ad made in ViewController in game scene - ios

I have an interstitial ad declared in GameViewController and want to call it every few times my game ends. I followed a tutorial where I would call the ad by a button but I need to call from GameScene but I don't know how to call across classes. Could I use a global variable between all classes or something?
Basically I want to call func adButton() in GameScene or maybe there is some better work around.
Also, is there any way to implement reward ads or does anyone have any good tutorial like it?
Thanks very much.
func createAndLoadInterstitial() -> GADInterstitial {
let interstitial = GADInterstitial(adUnitID: " unit id ")
let request1 = GADRequest()
interstitial.delegate = self
request1.testDevices = [ kGADSimulatorID, "2077ef9a63d2b398840261c8221a0c9b" ]
interstitial.loadRequest(request1)
return interstitial
}
func adButton() {
if (self.interstitial.isReady)
{
self.interstitial.presentFromRootViewController(self)
self.interstitial = self.createAndLoadInterstitial()
}
}

Use notifictionCenter to call the function
Add the first function in the viewDidLoad() and the second in the adButton()
In Swift 3
//In the gameviewcontroller
NotificationCenter.default.addObserver(self, selector: #selector(YourFunctionNameHere), name: "NSNotificationCreate" as NSNotification.Name, object: nil)
//In the gameScene use this to call the ad
NotificationCenter.default.post(name: "NSNotificationCreate" as NSNotification.Name, object: nil)
In Swift 2
//In the gameviewcontroller
NSNotificationCenter.defaultCenter().addObserver(self, selector: "YourFunctionNameHere", name: "NSNotificationCreate", object: nil)
//In the gameScene use this to call the ad
NSNotificationCenter.defaultCenter().postNotificationName("NSNotificationCreate", object: nil)

Related

Observers don't get called using NotificationCenter Swift 4.0

I have a two ViewControllers: ViewController and SecondViewController.
I added an observer to this two ViewControllers. In ViewController I also defined an IBAction to post the notification. I handle the notification via a closure in both ViewControllers. But only the closure in the ViewController gets called. The closure (and even the whole code) in the SecondViewController does not get called (I checked with debugger). The closure only contains a print-statement.
Here is my Code
//ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let nc = NotificationCenter.default
nc.addObserver(forName: Notification.Name(rawValue:"MyNotification"), object: nil, queue: nil) { (notification) in
print("I'm the : \(type(of: self))")
}
}
#IBAction func sendNotification(_ sender: UIButton) {
let nc = NotificationCenter.default
nc.post(name: Notification.Name(rawValue:"MyNotification"), object: nil, userInfo: ["message":"Hello there!", "Date:":Date()])
}
}
The ScondViewController
//SecondViewController
import UIKit
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let nc = NotificationCenter.default
nc.addObserver(forName: Notification.Name(rawValue:"MyNotification"), object: nil, queue: nil) { (notification) in
print("I'm the: \(type(of: self))")
}
}
}
The closure in ViewController gets called but the closure in SecondViewController does not. Maybe the reason is that SecondViewController does not get initialized before I post the notification. But how would a solution look like?
Any help is appreciated.
If this is one-to-one relationship you can also use the Delegate pattern instead. Although you are right, the notification observer is not yet called because you do not initialise before the post. So there shouldn't be a reason for a function to be called in the SecondViewController.
So if you only need that to update a variable value, you can do that somewhere else in a Variables class where both ViewControllers have access.

iOS unable to remove Notification observer. Deinit not getting called

I have a UIView similar to the one you can see below:
class ViewTaskViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
subscribeToNotifications()
}
func subscribeToNotifications() {
let notification = NotificationCenter.default
notification.addObserver(forName: Notification.Name(rawValue: "TimerUpdated"), object: nil, queue: nil, using: handleUpdateTimer)
print("Subscribed to NotificationCenter in ViewTaskViewController")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("TUFU TUFU TUFU")
NotificationCenter.default.removeObserver(self)
}
deinit {
print("DENINT")
}
#objc func handleUpdateTimer(notification: Notification) {
if let userInfo = notification.userInfo, let timeInSeconds = userInfo["timeInSeconds"] as? Int {
withUnsafePointer(to: &self.view) {
print("We got timeeeeee \(timeInSeconds) \($0)")
}
//do something here....
}
}
}
The issue I am having is that I am unable to remove the observers from this particular UIView when the user hits the back button and returns to another viewController.
ViewWillDisppear is called but deinit is not called. The strange thing is that if we remove subscribeToNotifications() from viewDidLoad() then the deinit is called.
The other issue is related to a memory leak. As you can see in the screenshot below, when the view does subscribe to notifications and the user leaves/re-enters the view, the memory usage increase.
Now compare that to when the subscribeToNotifications() is commented out, there is no increase in memory usage and only one instance of the viewController.
The conclusion is that there seems to be a correlation between the notification subscription creation of a new instance of the UIView hence the deinit is not being called.
I'd like to find out if there is a way we can deinitialize the view and unsubscribe from the notification.
Please let me know if you need further information. :)
I've found the removeObserver() only works if you use this version of addObserver()
notification.addObserver(self, selector:#selector(self.handleUpdateTimer), name: Notification.Name(rawValue: "TimerUpdated"), object: nil)
I'm guessing with the original version you aren't actually indicating who the observer is.
As #Spads said you can use
NotificationCenter.default.addObserver(self, selector: #selector(subscribeToNotifications), name: NSNotification.Name(rawValue: "TimerUpdate"), object: nil)
or the one you already have.
you can remove your notification by it's name or it's reference
NotificationCenter.default.removeObserver(self, name: "TimerUpdate", object: nil)
if you declared your notification at the top of your class then you can directly pass the reference of your notification to be removed in your case notification
NotificationCenter.default.removeObserver(notification)
You should store your newly added observer in a opaque object (NSObjectProtocol) and then call NotificationCenter.default.removeObserver(self.nameOfObserver)

Show Admob Interstitial ads between scenes in Swift SpriteKit

I would like to know how to set up Admob Interstitial ads when I present my GameOverScene. What should I do to show the ads only sometimes when the game gets over? And how do I implement this in Swift?
Im referring to this post How to call admob interstitial ad using swift, spritekit and xcode? but i'd like to know how to call the ads in between scenes.
EDIT
Here is the code I used to present the ad
class GameViewController: UIViewController, GADInterstitialDelegate {
var interstitial = GADInterstitial()
var intersitialRecievedAd = false
let defaults = NSUserDefaults.standardUserDefaults()
override func viewDidLoad() {
super.viewDidLoad()
interstitial.delegate = self
self.interstitial = createAndLoadAd()
let timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "checkIfAdIsToBeDisplayed:", userInfo: nil, repeats: true)
//Scene implementation, boring stuff, got nothing to do with the ads...
...
}
func checkIfAdIsToBeDisplayed(timer:NSTimer) {
if defaults.boolForKey("adToBeShown") == true && intersitialRecievedAd == true {
showInterstitial()
defaults.setBool(false, forKey: "adToBeShown")
intersitialRecievedAd = false
} else {
}
}
func interstitialDidReceiveAd(ad: GADInterstitial!) {
intersitialRecievedAd = true
}
func createAndLoadAd() -> GADInterstitial {
var ad = GADInterstitial(adUnitID: "...")
ad.delegate = self
let request = GADRequest()
request.testDevices = ["..."]
ad.loadRequest(request)
return ad
}
func showInterstitial(){
if self.interstitial.isReady {
self.interstitial.presentFromRootViewController(self)
self.interstitial = createAndLoadAd()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
This code uses a timer to constantly check whether the gameOverScene has been presented. When the gameOverScene IS presented, I assign true to the "adToBeShown" bool.
This is not the best method, so could anyone tell me how to directly call the ad when a scene is presented?
why dont you use NSNotificationCenter or delegates to call showInterstitial().
For example
In gameViewController add this in viewDidLoad
NSNotificationCenter.defaultCenter().addObserver(self, selector: "showInterstitial"), name:"showInterAdKey", object: nil);
and when you want to show the ad from your scenes you use
NSNotificationCenter.defaultCenter().postNotificationName("showInterAdKey", object: nil)
You could also use something like the helper I posted on github which makes this even easier and your ViewController stays clean https://github.com/crashoverride777/Swift-2-iAds-and-AdMob-Helper
You can also limit the frequency that Admob will show interstitial ads via the Admob website. In the settings for your interstitial advert, there are options to change the frequency of adverts popping up.

Calling ViewController's Method from App Delegate

Within my ViewController, Inbox, I'd like to call the method playAudio() from my App Delegate.
This is the method.
func playAudio(){
let nowPlaying = MPNowPlayingInfoCenter.defaultCenter()
let albumArtWork = MPMediaItemArtwork(image: UIImage(named: "testImage.jpg")!)
nowPlaying.nowPlayingInfo = [MPMediaItemPropertyTitle:"Sonnnngggg",
MPMediaItemPropertyArtist:"Arrrtttiiiissstttt",
MPMediaItemPropertyArtwork:albumArtWork]
audioPlayer.play()
}
And I'd like to call it from my App Delegate...
if event!.subtype == UIEventSubtype.RemoteControlPlay {
print("received remote play")
//audioPlayer.play()
Inbox.playAudio()
}
The one problem is that because I have a audioPlayer and everything within my Inbox ViewController, and that it's probably already playing audio, it doesn't make sense to make an instance of Inbox to call playAudio(). So, please let me know if there are any workarounds in Swift.
Thanks,
Liam
In AppDelegate change to:
if event!.subtype == UIEventSubtype.RemoteControlPlay {
print("received remote play")
//audioPlayer.play()
NSNotificationCenter.defaultCenter().postNotificationName("RemotePlayPressed", object: self)
}
Then in Inbox view controller's viewDidLoad add:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playAudio", name: "RemotePlayPressed", object: nil)
also add:
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
to Inbox view controller.
in your viewcontroller you reach your appdelegate via
(UIApplication.sharedApplication().delegate as! AppDelegate).playAudio()
You can instantiate the AppDelegate and call the function you want
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.someFunction()
But it not seems to be a good pratice...
NSNotificationCenter:
Use this code in the place you want to call the function:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "anotherFunction", name: "SomeNotification", object: nil)
change anotherFunction to the function name you want to call.
On AppDelegate:
NSNotificationCenter.defaultCenter().postNotificationName("SomeNotification", object: nil)

Pausing timer when app is in background state Swift

My ViewController.swift
func startTimer() {
timer = NSTimer().scheduleTimerWithTimerInvterval(1.0,target: self,selctor: Selector("couting"),userinfo: nil, repeats: true)
}
func pauseTimer() {
timer.invalidate()
println("pausing timer")
}
and this is appDelegate.swift
func applicateWillResignActive(application: UIApplication) {
viewController().pauseTimer()
println("closing app")
}
It is printing pausing timer and closing app but when I open again I see it never paused. How do I do it correctly?
You have to set an observer listening to when the application did enter background. Add the below line in your ViewController's viewDidLoad() method.
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("myObserverMethod:"), name:UIApplicationDidEnterBackgroundNotification, object: nil)
Add the below function to receive the notification.
func myObserverMethod(notification : NSNotification) {
println("Observer method called")
//You may call your action method here, when the application did enter background.
//ie., self.pauseTimer() in your case.
}
Happy Coding !!!
Updated Answer for Swift 5:
NotificationCenter.default.addObserver
(self,
selector: #selector(myObserverMethod),
name:UIApplication.didEnterBackgroundNotification, object: nil)
#objc func myObserverMethod() {
print("Write Your Code Here")
}
Accepted answer by #Suresh in Swift 3
Set an observer listening to when the application did enter background in your ViewController's viewDidLoad() method.
NotificationCenter.default.addObserver(self, selector: #selector(myObserverMethod), name:NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
Add the below function to receive the notification.
func myObserverMethod(notification : NSNotification) {
print("Observer method called")
//You may call your action method here, when the application did enter background.
//ie., self.pauseTimer() in your case.
}
Updated Answer for Swift 4:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(myObserverMethod), name:NSNotification.Name.UIApplicationDidEnterBackground, object: nil)
}
#objc func myObserverMethod() {
// Call your action method here, when the application did enter background.
}
You are creating a new object and calling pauseTimer() on it:
viewController().pauseTimer() // This line causes issue viewController(), creates a new instance
Instead of creating new object, either you should pass that instance to AppDelegate and call pauseTimer() on existing object or Listen for UIApplicationDidEnterBackgroundNotification notification in your view controller class and pause timer from there.

Resources