11

So I am trying to set up a simple iAd banner in my application but I am getting these two warnings in the output:

WARNING: More than 10 instances of ADBannerView or ADInterstitialView 
currently exist. This is a misuse of the iAd API, and ad performance will 
suffer as a result. This message is printed only once.

and

<Error>: CGAffineTransformInvert: singular matrix.

This is what I am using to implement my ADBannerView:

var adBannerView = ADBannerView()

func loadAds() {
    adBannerView = ADBannerView(frame: CGRect.zeroRect)
    adBannerView.center = CGPoint(x: adBannerView.center.x, y: view.bounds.size.height - adBannerView.frame.size.height / 2)
    adBannerView.delegate = self
    adBannerView.hidden = true
    view.addSubview(adBannerView)
}

//BannerView did load ad
func bannerViewDidLoadAd(banner: ADBannerView!) {
    adBannerView.hidden = false
}
//BannerView failed to load
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
    adBannerView.hidden = true
}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    loadAds()
    //(rest of the code is from here onwards)

I tried adding this to stop the first error: (hasn't worked)

//BannerView will disappear
override func viewWillDisappear(animated: Bool) {
    adBannerView.removeFromSuperview()
    adBannerView.delegate = nil
}
Daniel Storm
  • 18,301
  • 9
  • 84
  • 152
Luke Martin
  • 395
  • 4
  • 14
  • You're creating a new "ADBannerView" each time your view is loaded. Are you only loading this view once? – Daniel Storm Feb 18 '15 at 14:53
  • Thought so, no this view is being loaded lots of times. What would you recommend? Is there a way to unload the ADBannerView or is there a better way of doing it? – Luke Martin Feb 20 '15 at 02:17

3 Answers3

18

The issue is every time you load your view you are creating a new instance of ADBannerView. What we need to do is create a ADBannerView once in our AppDelegate.swift and then present this ADBannerView on which ever views we would like to have an iAd banner. This is also called a Shared iAd Banner. In this example, I've created an ADBannerView in my AppDelegate.swift and then added it to my ViewController.swift's view.

AppDelegate.swift

import UIKit
import iAd // Import iAd

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, ADBannerViewDelegate { // Include the delegate for our banner

    var window: UIWindow?
    var adBannerView = ADBannerView() // Create our one ADBannerView

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Set delegate and hide banner initially
        adBannerView.delegate = self
        adBannerView.hidden = true
        return true
    }

    func bannerViewDidLoadAd(banner: ADBannerView!) {
        print("bannerViewDidLoadAd")
        adBannerView.hidden = false
    }

    func bannerViewActionDidFinish(banner: ADBannerView!) {
        print("bannerViewActionDidFinish")
    }

    func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
        print("didFailToReceiveAdWithError: \(error)")
        adBannerView.hidden = true
    }

ViewController.swift

import UIKit

class ViewController: UIViewController {

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate // Create reference to our app delegate

    override func viewWillAppear(animated: Bool) {
        // Position
        appDelegate.adBannerView.center = CGPoint(x: view.frame.midX,
            y: view.frame.height - appDelegate.adBannerView.frame.height / 2)
        // Add to view
        view.addSubview(appDelegate.adBannerView)
    }

Don't forget to remove the code from your viewWillDisappear(animated: Bool) function that you added previously. If you click on the banner and then dismiss it this function will be called and removing our banner from our view and setting our banners delegate equal to nil too soon will cause issues.

Daniel Storm
  • 18,301
  • 9
  • 84
  • 152
  • 1
    Thank you so much! This worked perfectly, was a massive help :) – Luke Martin Feb 21 '15 at 09:07
  • Are you sure this is the same banner instance as in appDelegate? Not sure if I am getting this shared banner instance correctly, but the line that seem weird is 'self.appDelegate.adBannerView = ADBannerView(frame: CGRect.zeroRect)'. This is an initialiser, therefore you created a different object. – potato Sep 24 '15 at 18:18
  • @krompir2 thank you for pointing that out. I've reimplemented the `ADBannerView` and updated it for Swift 2.0. – Daniel Storm Sep 27 '15 at 10:21
  • @DanielStorm strangely, but it crashes my app and says that it's because of `bannerViewDidLoadAd` function – Burundanga Sep 29 '15 at 15:59
  • @Burundanga Make sure you're including the `iAd.framework` in your project, Build Phases>Link Binary With Libraries>Click the + to search for and include the framework. Also make sure you've included the delegate for the `ADBannerView` in your `AppDelegate.swift`, `ADBannerViewDelegate`. – Daniel Storm Sep 30 '15 at 12:15
  • This approach works and gets rid of the error, but it still has to create the new view the new ad for every tab. Rapidly switching tabs still causes the blank ad banner to be added occasionally. The best approach I found to solve it and avoid modifying view controllers is to use iAd Suite example published by Apple: https://developer.apple.com/library/ios/samplecode/iAdSuite_Storyboard/Introduction/Intro.html#//apple_ref/doc/uid/DTS40013458-Intro-DontLinkElementID_2 – Ilya Vinogradov Mar 22 '16 at 15:46
  • How would I modify the `ViewController.swift` code so as to pin the banner to the bottom of each screen/view? – Katherine Jenkins May 15 '16 at 18:23
  • @KatherineJenkins I'm not sure of the auto layout code exactly, but you could pin it to the bottom and align it to x as I've mentioned here, http://stackoverflow.com/a/34635924/2108547 – Daniel Storm May 15 '16 at 18:27
  • @DanielStorm Thanks for the reference kind sir ;) – Katherine Jenkins May 15 '16 at 18:34
1

If you don't want to care about the size, position, error handling and the delegate methods of your banner ad you can also use:

self.canDisplayBannerAds = true

This solved the error in my App, because Apple takes also care about the number of instances

I've written a short tutorial about this: link

Stefan
  • 5,203
  • 8
  • 27
  • 51
1

If you want the banner to persist between the tabs and not disappear when rapidly switching tabs, you've got to do the iAd Suite approach: http://developer.apple.com/library/ios/#samplecode/iAdSuite/Introduction/Intro.html (Check out BannerViewController.m file - not in Swift, but it's not hard to convert it)

This approach also doesn't require you to modify any go the view controllers within your tabs. You simply have to have a relationship segue from your tab bar controller to a View Controller that has container view embedded into it. Do that in your storyboard. Also, you need to set Custom Class to BannerViewController for each tab, and embed your content into the embedded view. Take a look at this post for details on how to do it it the Storyboard: https://stackoverflow.com/a/16205420/5007500

If you are not using Storyboard - you need to set BannerViewController as parent view controller for each of your tabs.

Community
  • 1
  • 1
Ilya Vinogradov
  • 746
  • 6
  • 7