CollectionView choppy scrolling when loading admanager banner ads - ios

I have a collection view with n sections and m rows. The number of sections and rows are fetched from an API. Typically 18 sections with 10 rows each. Each cell item is just one UIImageView and two UILabels.
It all was working smooth scrolling until I added google ad manager banner ads in the cells. For that I just created a new section with number of item 1 in that section. And gave the size of cell the full width and respective height of the banner ad. I followed the UITableView example of google ad manager to implement in UICollectionView.
But now when ever the collection view is loading, or reloading through UIRefreshControl, for about 1-2 seconds it gives choppy scrolling behaviour. After that scrolls smoothly.
extension HomeVideosViewController {
func loadBannerAd() {
// call ad requests
let filteredIndices = self.homeVideosDatasource.datasource.indices.filter { (index) -> Bool in
if self.homeVideosDatasource.datasource[index].section_type == "banner_ad" {
return true
}
return false
}
for index in filteredIndices {
if let bannerAd = self.homeVideosDatasource.datasource[index].datasource.first as? BannerAd {
// create banner ad object
let bannerView: DFPBannerView!
if bannerAd.is_mid_ad == true {
bannerView = DFPBannerView(adSize: kGADAdSizeLargeBanner)
} else {
let frame = { () -> CGRect in
if #available(iOS 11.0, *) {
return self.view.frame.inset(by: self.view.safeAreaInsets)
} else {
return self.view.frame
}
}()
let viewWidth = frame.size.width
bannerView = DFPBannerView(adSize: GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth))
}
// save index as tag for banner ads
bannerView.tag = index
bannerView.adUnitID = bannerAd.ad_code
bannerView.rootViewController = self
bannerView.delegate = self
bannerView.load(DFPRequest())
// replace bannerAd with banner view
var updatedBannerAd = bannerAd
updatedBannerAd.requestBannerView = bannerView
self.homeVideosDatasource.datasource[index].datasource = [updatedBannerAd]
}
}
}
func addBannerViewToView(_ bannerView: GADBannerView) {
DispatchQueue.main.async {
let homeSection = self.homeVideosDatasource.datasource[bannerView.tag]
// replace bannerAd with banner view
if let bannerAd = homeSection.datasource.first as? BannerAd {
var updatedBannerAd = bannerAd
updatedBannerAd.receivedBannerView = bannerView
updatedBannerAd.adRequestComplete = true
homeSection.datasource = [updatedBannerAd]
// replace home section with banner ads
self.homeVideosDatasource.datasource[bannerView.tag] = homeSection
// check if ads requests are complete
self.checkForIncompleteAds()
}
}
}
}
extension HomeVideosViewController: GADBannerViewDelegate {
/// Tells the delegate an ad request loaded an ad.
func adViewDidReceiveAd(_ bannerView: GADBannerView) {
print("adViewDidReceiveAd for index : \(bannerView.tag)")
DispatchQueue.global(qos: .background).async {
self.addBannerViewToView(bannerView)
}
}
/// Tells the delegate an ad request failed.
func adView(_ bannerView: GADBannerView,
didFailToReceiveAdWithError error: GADRequestError) {
print("adView:didFailToReceiveAdWithError: \(error.localizedDescription)")
let homeSection = self.homeVideosDatasource.datasource[bannerView.tag]
// replace bannerAd with banner view
if let bannerAd = homeSection.datasource.first as? BannerAd {
var updatedBannerAd = bannerAd
updatedBannerAd.adRequestComplete = true
homeSection.datasource = [updatedBannerAd]
// replace home section with banner ads
self.homeVideosDatasource.datasource[bannerView.tag] = homeSection
// check if ads requests are complete
self.checkForIncompleteAds()
}
}
func checkForIncompleteAds() {
let homeBannerAdsNoCompleted = self.homeVideosDatasource.datasource.filter { (homeVideosSection) -> Bool in
if homeVideosSection.section_type == "banner_ad" {
if let bannerAd = homeVideosSection.datasource.first as? BannerAd {
return !bannerAd.adRequestComplete
}
return false
} else {
return false
}
}
if homeBannerAdsNoCompleted.count == 0 {
// Reload CollectionView
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
}
}
To narrow down the issue I tried commenting where I was placing the banner ad inside the cell. But the choppiness was still there.
Then I tried commenting where addBannerViewToView to see if placing the ad in datasource was making the issue, but still this method was not the issue.
Next I tried commenting checkForIncompleteAds(), but this was also not the issue.
Most probably the culprit here is loadAds(). When I commented this out the scrolling was smooth. But i'm not sure what could be the potential fixes for this. I cant even put it on background thread.
Any help is appreciated. Thanks

Try reloading collectionView i.e. self.collectionView.reloadData() also after ads view is loaded, not only when after homeBannerAdsNoCompleted.count == 0
//Reload CollectionView
DispatchQueue.main.async {
self.collectionView.reloadData()
}

So the problem exactly lies in requesting the ads (bannerView.load(DFPRequest())), this is called on the main thread and here in my code calling it in a loop (of 4 for now) blocks the main thread.
Instead of calling it in a loop Google recommends calling first request, then after completion of that request, call second request. That is there should be at most one active request on main thread.
So I added two properties:
var adsToLoad = [GADBannerView]()
var loadStateForAds = [GADBannerView: Bool]()
adsToLoad keep the ads to be requested.
loadStateForAds keeps the ad vs bool value to know which ads are successful and which ads are failed.
Then this method requests ads one by one.
func preloadNextAd() {
if !adsToLoad.isEmpty {
let ad = adsToLoad.removeFirst()
let adRequest = GADRequest()
ad.load(adRequest)
}
}
preloadNextAd() is called first when ads are loaded into adsToLoad.
// load banner ads
self.loadBannerAd()
self.preloadNextAd()
and then from GAD delegates methods.
// MARK: - GADBannerView delegate methods
func adViewDidReceiveAd(_ adView: GADBannerView) {
// Mark banner ad as succesfully loaded.
loadStateForAds[adView] = true
// Load the next ad in the adsToLoad list.
preloadNextAd()
}
func adView(
_ adView: GADBannerView,
didFailToReceiveAdWithError error: GADRequestError
) {
print("Failed to receive ad: \(error.localizedDescription)")
// Load the next ad in the adsToLoad list.
preloadNextAd()
}
There is still a little choppiness but greatly reduced.

Related

Replace view if no ads is shown - AdMob

I've an application which uses AdMob as advertisement. And every time no ads is shown it's just a "view" with nothing inside it. I am now looking to replace the empty space and add an image. Is this possible?
So, how can I replace my "view" if no ads is shown, and add an image inside it?
I've tried to googling around, but could not find anything about this.
//Request Advertisement
let request = GADRequest()
request.testDevices = [kGADSimulatorID]
//Set up advertisement
advertisementBanner.adUnitID = "ca-app-pub-7225493999040026/4779408290"
advertisementBanner.rootViewController = self
advertisementBanner.delegate = self
advertisementBanner.load(request)
The current result is: If no ads is available there will be just an empty space in the view. I wanna replace this empty space with an image.
Use GADBannerViewDelegate to do this
func adViewDidReceiveAd(_ bannerView: GADBannerView) {
print("adViewDidReceiveAd")
}
func adView(_ bannerView: GADBannerView,
didFailToReceiveAdWithError error: GADRequestError) {
print("adView:didFailToReceiveAdWithError: \(error.localizedDescription)")
cnstAddViewHeight.constant = 0.0 // you can hide your view or replace with image here
}

Swift Admob Interstitial Error

This is pretty long but it's probably a really easy fix.
Most of this is code, just skip to the bottom and there'll be a tl;dr
Hey, so I've followed about 10 tutorials on getting Admob interstitials to work in my Swift Spritekit game. Except all the tutorials I've seen use an IBAction with a button.
Currently I would like the ads to pop up every once in a while on the menu. (just to begin with, I might change it later).
This all works perfectly, but once I hit the play button (going to a different scene) and then return to the menu scene. (GameScene) The interstitial function no longer happens. There is no error, it just doesn't do it any more until the app is completely closed and re-opened.
Here's the code.
In my GameViewController class I have:
var interstital: GADInterstitial!
And in the GameViewController did load I have:
if let scene = GameScene(fileNamed:"GameScene") {
let skView = self.view as? SKView
skView!.ignoresSiblingOrder = false
scene.scaleMode = .AspectFill
scene.viewController = self
skView!.presentScene(scene)
interstital = GADInterstitial(adUnitID: "ca-app-pub-9776687746813194/9687097060")
let request = GADRequest()
interstital.loadRequest(request)
Also in the GameViewController class I have these functions:
func ShowAd() {
print("doing the showadfunc now")
if (interstital.isReady) {
print("there is an inter ready")
interstital.presentFromRootViewController(self)
interstital = CreateAd()
}
else{
print("The interstitial wasn't ready.")
}
}
func CreateAd() -> GADInterstitial {
let interstital = GADInterstitial(adUnitID: "ca-app-pub-9776687748683194/9687247060")
interstital.loadRequest(GADRequest())
return interstital
}
In my GameScene's (The menu) class I have:
var viewController: GameViewController!
And in my GameScene's class I have this function for displaying an interstitial ad.
func adThing(){
//viewController?.ShowAd()
print("starting the ad function")
let waitForInterstitial = SKAction.waitForDuration(15.0)
let waitForInterstitialShort = SKAction.waitForDuration(3.0)
let showInterstitialAd = SKAction.runBlock({self.viewController?.ShowAd(); print("the function has been called..")})
let waitThenShowInterstitial = SKAction.sequence([showInterstitialAd,waitForInterstitial])
let waitThenShowInterStitialForever = SKAction.repeatActionForever(waitThenShowInterstitial)
//self.runAction(waitThenShowInterStitialForever)
self.runAction(waitForInterstitialShort, completion: {
print("its waited 3 seconds and will now start the ad thingo")
self.runAction(waitThenShowInterStitialForever)
})
print("done")
}
So, I call the ShowAd function (which is located in gameviewcontroller) in my GameScene every 20 seconds, (I have confirmed it at least thinks it is calling the function.) It works perfectly when the app is opened to begin with. But when I change scene and then return to the menu scene (GameScene), the Prints in my GameScene function keep happening, and my code thinks that it is calling the ShowAd function, but it seems that nothing is happening, no interstitials pop up, not even the prints that are in the ShowAd function in the GameViewController.
So it seems like after I change scenes and return, my game forgets what the GameViewController is. If I refer to the GameViewController without a '?' it will crash my game with the error "unexpectedly found nil while unwrapping an optional." So after changing scenes, maybe GameViewController becomes nil? How can I fix this.
Please help me!!! (I'm new to programming in case you can't tell. I know it must be tempting to make a snide comment about my code, it is really bare bones and not that good at the moment.)
Thank you so much if you can help me, and wow.. thanks for reading all this.. ;)
You problem most likely is that once you transition to a new scene the viewController property is set to nil hence a crash if you use !.
In general its not the best practice to reference the viewController in your SKScenes, you should use Delegation or NSNotification Center.
1) Notification Center (easiest way)
In your ViewController where you have the function to show ads add a NSNotificationCenter observer in ViewDidLoad
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(showAd), name: "ShowInterAdKey", object: nil)
(Selector is the function to call and name is the key to reference this observer)
Than in your SKScenes when you want to show the ad you simply post the notification
NSNotificationCenter.defaultCenter().postNotificationName("ShowInterAdKey", object: nil)
2) For delegation examples check out these articles.
http://stephenradford.me/creating-a-delegate-in-swift/
https://www.natashatherobot.com/ios-weak-delegates-swift/
3) I also noticed that you are not preloading the ads before you show them, which is not very efficient and can cause delays showing ads.
You should call
interstital = CreateAd()
in viewDidLoad so it will load the first ad ASAP. Than you should use the adMob delegate method
func interstitialDidDismissScreen(ad: GADInterstitial!) {
// load next ad
interstital = CreateAd()
to immediately load the next ad once the current one is closed.
To use the delegates you can create an extension in ViewController
extension MyViewController: GADInterstitialDelegate {
func interstitialDidReceiveAd(ad: GADInterstitial!) {
print("AdMob interstitial did receive ad from: \(ad.adNetworkClassName)")
}
func interstitialWillPresentScreen(ad: GADInterstitial!) {
print("AdMob interstitial will present")
// pause game/app
}
func interstitialWillDismissScreen(ad: GADInterstitial!) {
print("AdMob interstitial about to be closed")
}
func interstitialDidDismissScreen(ad: GADInterstitial!) {
print("AdMob interstitial closed, reloading...")
interstitial = createAd()
}
func interstitialWillLeaveApplication(ad: GADInterstitial!) {
print("AdMob interstitial will leave application")
// pause game/app
}
func interstitialDidFailToPresentScreen(ad: GADInterstitial!) {
print("AdMob interstitial did fail to present")
}
func interstitial(ad: GADInterstitial!, didFailToReceiveAdWithError error: GADRequestError!) {
print(error.localizedDescription)
}
}
To make sure these get called go to your createAd function and add this line before returning the ad
let interstitial = ...
interstitial.delegate = self
Finally your showAd method should look like this
func showAd() {
print("doing the showadfunc now")
if (interstital.isReady) {
print("there is an inter ready")
interstital.presentFromRootViewController(self)
} else{
print("The interstitial wasn't ready, reloading again.")
interstital = CreateAd()
}
}
4) You can also check out my helper on gitHub if you are looking for a more reusable solution.
https://github.com/crashoverride777/Swift-AdMob-AppLovinTVOS-CustomAds-Helpers
As a general tip you should also follow the swift naming conventions, your func and properties should start with small letters. Only classes, structs, enums and protocols should start with capital letters.
It makes your code harder to read for yourself and on stackoverflow because it is marked blue but shouldn't. You are sometimes doing and sometimes not.
Hope this helps
I'd bet this is your issue:
if (interstital.isReady) {
print("there is an inter ready")
interstital.presentFromRootViewController(self)
interstital = CreateAd()
You're presenting your interstitial and then immediately overwriting your interstitial. You should be implementing the GADInterstitial's delegate methods and calling your func CreateAd() -> GADInterstitial once func interstitialDidDismissScreen(ad: GADInterstitial!) is called.
if your device keeps crashing because of:
interstitial.delegate = self
then put it in your CreatAndLoadInterstitial(), not your viewDidLoad()

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.

Interstitial iAds in SpriteKit?

I'm using SpriteKit for my iOS app, and need some full-screen (or sometimes called "interstitial" iAds to pop up every so often. I can figure out the code for when it happens, but I need to know how to add iAds without necessarily changing the View Controller.
I tried a [tutorial][1] by Techotopia on Interstitial iAds, but to do it I need to transition between actual View Controllers. Well, I tried this, but whenever transitioning back from the iAd view controller to the GameViewController, it messed it all up. The code in the GameViewController.m says that it is initially set to the main menu of my game (an SKScene). So when I try transitioning back from the iAd, instead of keeping the same SKScene up, it goes strait to my main menu scene.
I need these answers:
Is there some way other than using two View Controllers to show Interstitial iAds?
If not, how can I get around this problem?
Would this problem also occur if I were to change my "Interstitial iAds" to "Pre-roll Video iAds?"
-
EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT! EDIT!
-
I ended up deciding to use crashoverride777's answer, and creating an Objective-C bridging header to convert his Swift code to Objective-C. But when referencing the Ads.swift's variable presentingViewController, it ends up being nil. Here is my code in GameViewController.m:
// Set up interstitial iAds.
Ads *adsClass = [[Ads alloc] init];
Ads *adsInstance = [Ads sharedInstance];
adsInstance.presentingViewController = self;
This, however, doesn't do anything. The function showInterAd gets called from my GameScene.m like it's supposed to, but no ad appears. In my Ads.swift, I added a log to see if presentingViewController is indeed nil.
print("iAd inter showing")
if (self.presentingViewController != nil) {
print("presentingViewController != nil")
iAdInterAdView.frame = presentingViewController.view.bounds
presentingViewController.view.addSubview(iAdInterAdView)
iAdInterAd!.presentInView(iAdInterAdView)
UIViewController.prepareInterstitialAds()
iAdInterAdView.addSubview(iAdInterAdCloseButton)
} else {
print("presentingViewController == nil")
}
The log comes out like this every time: "presentingViewController == nil". I'm not sure what's going wrong, here.
You can make use of my helper I posted on github. Its was made specifically for spritekit and you can call ads from anywhere without delegates etc or changing view controllers.
https://github.com/crashoverride777/Swift-2-iAds-and-AdMob-Helper
I think having a look at that helper should give you a good idea of where to start. Here is a cut down example of how it could look just for iAds Inter ads.
This is in swift so I am not sure if it is still helpful for you.
import iAd
class Ads: NSObject {
// MARK: - Static Properties
/// Shared instance
static let sharedInstance = Ads()
// MARK: - Properties
/// Presenting view controller
var presentingViewController: UIViewController!
/// iAd inter ad
private var iAdInterAd: ADInterstitialAd?
/// iAd inter ad view
private var iAdInterAdView = UIView()
/// iAd inter ad close button
private var iAdInterAdCloseButton = UIButton(type: UIButtonType.System)
// MARK: - Init
private override init() {
super.init()
print("Ads helper init")
iAdInterAd = iAdLoadInterAd()
}
// MARK: - User Methods
/// Show inter ad
func showInterAd() {
iAdShowInterAd()
}
/// Show inter ad randomly (33% chance)
func showInterAdRandomly() {
let randomInterAd = Int(arc4random() % 3)
print("randomInterAd = \(randomInterAd)")
if randomInterAd == 1 {
iAdShowInterAd()
}
}
/// Remove all ads
func removeAllAds() {
print("Removed all ads")
if iAdInterAd != nil {
iAdInterAd!.delegate = nil
iAdInterAdCloseButton.removeFromSuperview()
iAdInterAdView.removeFromSuperview()
}
}
// MARK: - Internal Methods
/// iAd load inter ad
private func iAdLoadInterAd() -> ADInterstitialAd {
print("iAd inter ad loading...")
let iAdInterAd = ADInterstitialAd()
iAdInterAd.delegate = self
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
iAdInterAdCloseButton.frame = CGRectMake(18, 18, 27, 27)
} else {
iAdInterAdCloseButton.frame = CGRectMake(13, 13, 22, 22)
}
iAdInterAdCloseButton.layer.cornerRadius = 11
iAdInterAdCloseButton.setTitle("X", forState: .Normal)
iAdInterAdCloseButton.setTitleColor(UIColor.grayColor(), forState: .Normal)
iAdInterAdCloseButton.backgroundColor = UIColor.whiteColor()
iAdInterAdCloseButton.layer.borderColor = UIColor.grayColor().CGColor
iAdInterAdCloseButton.layer.borderWidth = 2
iAdInterAdCloseButton.addTarget(self, action: "iAdPressedInterAdCloseButton:", forControlEvents: UIControlEvents.TouchDown)
return iAdInterAd
}
/// iAd show inter ad
private func iAdShowInterAd() {
guard iAdInterAd != nil else {
print("iAd inter is nil, reloading")
iAdInterAd = iAdLoadInterAd()
return
}
if iAdInterAd!.loaded {
print("iAd inter showing")
iAdInterAdView.frame = presentingViewController.view.bounds
presentingViewController.view.addSubview(iAdInterAdView)
iAdInterAd!.presentInView(iAdInterAdView)
UIViewController.prepareInterstitialAds()
iAdInterAdView.addSubview(iAdInterAdCloseButton)
//pauseTasks() // not really needed for inter as you tend to show them when not playing.
} else {
print("iAd inter not ready, reloading again...")
iAdInterAd = iAdLoadInterAd()
}
}
/// iAd inter ad pressed close button
func iAdPressedInterAdCloseButton(sender: UIButton) { // dont make private as its called with a selector
print("iAd inter closed")
iAdInterAd!.delegate = nil
iAdInterAdCloseButton.removeFromSuperview()
iAdInterAdView.removeFromSuperview()
iAdInterAd = iAdLoadInterAd()
//resumeTasks() // not really needed for inter as you tend to not show them during gameplay
}
/// Pause tasks in the app/game
private func pauseTasks() {
// Pause app/game, music etc here.
// you could use NSNotifactionCenter or Delegates to call methods in other SKScenes / ViewControllers
}
/// Resume tasks in the app/game
private func resumeTasks() {
// Resume app/game, music etc here.
// you could use NSNotifactionCenter or Delegates to call methods in other SKScenes / ViewControllers
}
}
// MARK: - Delegates iAd Inter
extension Ads: ADInterstitialAdDelegate {
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
print("iAd inter did load")
}
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
print("iAd inter did unload")
}
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
print("iAd inter error \(error)")
iAdInterAd!.delegate = nil
iAdInterAdCloseButton.removeFromSuperview()
iAdInterAdView.removeFromSuperview()
}
}
Now you simply call
Ads.sharedInstance.presentingViewController = self
in your GameViewController before doing anything else. This will init the helper and preload the first inter ad.
Than you simply call these anywhere you would like inter ads to show
GameData.sharedInstance.showInterAd()
or
GameData.sharedInstance.showInterAdRandomly() // 33% chance for ad
Presenting interstitial in sprite kit is almost identical to in other parts of the app. The only difference is you present the add by calling all the iAd methods with 'self.view'. This gets the view the SKScene is presented in and present the iAd over it
also this can be used to present interstitial without switching view controllers
currentView.requestInterstitialAdPresentation()
to request from in the scene:
self.view?.requestInterstitialAdPresentation()
Notice how in the function call it says request. That is why it only shows up sometimes. When you 'request' an ad the device sends a request to apple asking for an ad. If you get a response back in a reasonable amount of time then the ad will present. If you do not get a response back in a reasonable amount of time (most likely due to poor internet) there the ad won't present because theres nothing to present. However if you request once and it doesn't present, the next time you ask it will definitely present because you already have an ad loaded from the last time you requested but it never got presented.

iAd Interstitials not showing consistently? And not at all on the simulator

iAd interstitials aren't showing up at all on the iPhone simulator, and they don't show up consistently on my iPhone. I've gone to the Developer settings, changed the fill rate to 100%, and turned on Unlimited Ad Presentation. No difference... an interstitial will generally show the first time it's supposed to, and then won't show again for anywhere from a few minutes to fifteen minutes. No idea what is causing the difference in time.
Also, there doesn't seem to be a way to track if the interstitial is going to show or not / if it actually showed or didn't. I realize there's an interstitial delegate, but it seems that isn't used anymore. The way I am calling my interstitial is using viewController.interstitialPresentationPolicy = ADInterstitialPresentationPolicy.Automatic
Thanks!
So it seems that using requestInterstitialAdPresentation is intended to only be used when your ADInterstitialPresentationPolicy is set to Automatic. When implementing your interstitials using a Manual ADInterstitialPresentationPolicy you must use presentInView to present the ad at your own intervals. When presenting your interstitial in this manner it does not load with its own close button to dismiss itself. So, what I've done is created a UIView to present the interstitial in and used the interstitials delegate methods to dismiss the UIView. The inconsistency with receiving an ad from the iAd network still arises when testing. Sometimes you receive an ad, sometimes it fails to load which allows us to request a new ad, and sometimes nothing happens at all. This just seems to be the nature of iAd's interstitials.
import UIKit
import iAd // Import iAd
class ViewController: UIViewController, ADInterstitialAdDelegate { // Include the delegate
var iAdInterstitial = ADInterstitialAd() // Our ad
var iAdInterstitialView = UIView() // View to present our ad in
var adLoaded = false // Bool to keep track if an ad is loaded or not
override func viewDidLoad() {
super.viewDidLoad()
setupAd()
}
func setupAd() {
// Set presentation to manual so we can choose when to present the interstitial
// Setting this will also fetch an interstitial ad for us
self.interstitialPresentationPolicy = ADInterstitialPresentationPolicy.Manual
iAdInterstitial.delegate = self // Set the delegate
// Make our view the same size as the view we will be presenting in
iAdInterstitialView.frame = self.view.bounds
}
func requestNewAd() {
// This will fetch an ad for us
ViewController.prepareInterstitialAds()
println("Requesting new ad")
}
#IBAction func presentAdButton(sender: AnyObject) {
if (adLoaded) {
// We have an ad that is loaded so lets present it
self.view.addSubview(iAdInterstitialView)
iAdInterstitial.presentInView(iAdInterstitialView)
}
else {
// No ad has been loaded
println("Ad not loaded")
}
}
func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
// Kinda works as expected
// Sometimes is called prematurely
// Sometimes takes minutes after ad is dismissed to be called
println("interstitialAdDidUnload")
// Get new ad
adLoaded = false
iAdInterstitialView.removeFromSuperview()
requestNewAd()
}
func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
// Failed to load ad so lets try again
println("didFailWithError: \(error)")
requestNewAd()
}
func interstitialAdWillLoad(interstitialAd: ADInterstitialAd!) {
// There is an ad and it has begun to download
println("interstitialAdWillLoad")
}
func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
// We got an ad
println("interstitialAdDidLoad")
adLoaded = true
}
func interstitialAdActionShouldBegin(interstitialAd: ADInterstitialAd!, willLeaveApplication willLeave: Bool) -> Bool {
println("interstitialAdActionShouldBegin")
return true;
}
func interstitialAdActionDidFinish(interstitialAd: ADInterstitialAd!) {
// Done with this ad. Lets get a new one
println("interstitialAdActionDidFinish")
iAdInterstitialView.removeFromSuperview()
adLoaded = false
requestNewAd()
}

Resources