Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iAd doesn't show asynchronously once its delegate method is called

I have replicated the iAdSuite with Storyboards in swift and the iAd works all fine across all view controllers, except that when the delegate method bannerViewDidLoadAd(banner: ADBannerView!) is called the banner view does not appear instantly. I have to either rotate the simulator or go to another tab so that it appears.

I think this is the part of Apple sample code in Objective-C that I could not "translate" to swift? which may well be causing the iAd not show asynchronously once loaded...

+ (BannerViewManager *)sharedInstance
{
    static BannerViewManager *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[BannerViewManager alloc] init];
    });
    return sharedInstance;
}

This is my BannerViewManager class with the ADBannerViewDelegate methods.

class BannerViewManager: NSObject, ADBannerViewDelegate {

    // MARK: - Shared instance
    static let sharedInstance = BannerViewManager()

    var bannerView: ADBannerView!
    var bannerViewControllers: NSMutableSet!

    override init() {
        super.init()

        bannerView = ADBannerView(adType: .Banner)
        bannerViewControllers = NSMutableSet()
        bannerView.delegate = self
    }

    func addBannerViewController(controller: BannerViewController) {
        bannerViewControllers.addObject(controller)
    }

    func removeBannerViewController(controller: BannerViewController) {
        bannerViewControllers.removeObject(controller)
    }

    // MARK: - Ad banner view delegate methods

    func bannerViewDidLoadAd(banner: ADBannerView!) {
        NSLog("bannerViewDidLoadAd")

        for bannerViewController in bannerViewControllers {
            (bannerViewController as! BannerViewController).updateLayout()
        }
    }

    func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
        NSLog("didFailToReceiveAdWithError %@", error);

        for bannerViewController in bannerViewControllers {
            (bannerViewController as! BannerViewController).updateLayout()
        }
    }

    func bannerViewActionShouldBegin(banner: ADBannerView!, willLeaveApplication willLeave: Bool) -> Bool {
        NSNotificationCenter.defaultCenter().postNotificationName(BannerViewActionWillBegin, object: self)
        return true
    }

    func bannerViewActionDidFinish(banner: ADBannerView!) {
        NSNotificationCenter.defaultCenter().postNotificationName(BannerViewActionDidFinish, object: self)
    }
}

EDIT

I have managed to convert the objective-C code above to swift using this post on SO but I still have the same problem. The iAd doesn't appear once its loaded. There's got to be some sort of change to the view so that it does, either rotating device or tapping another tab, etc...

So now my sharedInstance looks like this:

    static var sharedInstance: BannerViewManager {
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var instance: BannerViewManager? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = BannerViewManager()
        }
        return Static.instance!
    }
like image 224
Ahmed Khedr Avatar asked Dec 21 '15 19:12

Ahmed Khedr


1 Answers

I think I figured out what the problem is. It has nothing to do with the way I initialise the shared instance of the BannerViewManager class. In the matter of fact it turned out to give exactly the same behaviour whether using dispatch_once or the new swift 2.0 way.

The thing that caused the iAd not to show instantaneously when bannerViewDidLoadAd was invoked is that viewDidLayoutSubviews was actually never called!

I had to add some print statements here and there. Both in my code and Apple sample code to reach this conclusion.

So setNeedsLayout instead of layoutIfNeeded forced trigger the viewDidLayoutSubviews

like image 92
Ahmed Khedr Avatar answered Sep 19 '22 16:09

Ahmed Khedr