2

I have an app that uses a xib defined AdBannerView. If the app runs on an iPhone (4 or 5) everything works as expected, ads get shown, banners get hidden / shown etc.

However if the app is run on an iPad it crashes after repeatedly failing to receive the ad. Examining the call stack shows repeated calls to bannerView:didFailToReceiveAdWithError:

Watching allocations while its running on an iPad shows continuous memory growth until the crash.

Messing with the network connectivity doesn't seem to alter the fact that it works on an iPhone but not on an iPad.

I read this SO question which instead of using a AdBannerView in the xib it creates it on the fly and then releases it appropriately when the ad fails to load.

EDIT:

I changed the devices setting in the project file from iPhone to Universal. The app now does not crash but of course all the views are now 'messed up'. So one option for a fix would be to implement the iPad idiom throughout the app.

My questions are -

  1. What is going on? No, really! I'm confused as to why there is differing behaviour between devices.

  2. Should I look to creating the AdBannerView programmatically? That kind of feels defeatist.

  3. How can I fix this behaviour?

Here is the code

#pragma mark ADBannerViewDelegate

- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
    [self showBanner];
}

- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
    [self hideBanner];
}

- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
    [self hideBanner];
}

#pragma mark ADBanner helpers

- (void)hideBanner
{
    CGRect hiddenFrame = self.bannerDisplayFrame;
    hiddenFrame.origin.y = self.view.frame.size.height;

    [UIView animateWithDuration:0.3f
                     animations:^{
                         [self.adBannerView setFrame:hiddenFrame];
                     }
                     completion:^(BOOL finished)
                     {
                         if (finished)
                         {
                             [self.adBannerView setAlpha:0.0f];
                         }
                     }];
}

- (void)showBanner
{
    [self.adBannerView setAlpha:1.0f];
    [UIView animateWithDuration:0.3f
                     animations:^{
                         [self.adBannerView setFrame:self.bannerDisplayFrame];
                     }
                     completion:^(BOOL finished)
                     {
                         if (finished)
                         {
                             [NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:@selector(hideBanner) userInfo:nil repeats:NO];
                         }
                     }];

}
Community
  • 1
  • 1
Damo
  • 12,840
  • 3
  • 51
  • 62
  • is your application universal? – Vlad Z. May 09 '13 at 21:54
  • It's set for iPhone. But it was rejected by Apple and they stated they tested it on an iPad and it crashed. I checked and yes it did crash! – Damo May 09 '13 at 21:56
  • 1
    check this out http://stackoverflow.com/questions/10243188/iad-not-working-on-ipad. – Vlad Z. May 09 '13 at 21:58
  • Okay - it now runs but obviously my XIBs dont take account of the iPad idiom. Good shout, if all else fails I know I can make it a universal app. I shall add a comment into the question. – Damo May 09 '13 at 22:05

3 Answers3

1

It looks like you are creating new iAD banner views every time, the suggested way is to use a shared one throughout the whole app. This might be the reason of continuous memory growth in your app and you will definitely end up with a warning from apple servers if you request ads too many times. Have a look at here in Apple's documentation for more details iAD Best Practices

This is how I implemented shared adbannerview, it might be of help.

AppDelegate.h

@property (nonatomic, strong) ADBannerView *adBanner;

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ...
    adBanner = [[ADBannerView alloc] initWithFrame:CGRectZero];
    adBanner.delegate = self;
    adBanner.backgroundColor = [UIColor clearColor];
    adBanner.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
    ...
}

prefix.pch or better in a header file included in prefix.pch

#define SharedAdBannerView ((AppDelegate *)[[UIApplication sharedApplication] delegate]).adBanner

And I have a implemented a uiviewcontroller category to handle iADs

@implementation UIViewController (SupportIAD)

-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
    SharedAdBannerView.hidden = FALSE;
}

-(void) bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
    SharedAdBannerView.hidden = TRUE;
}

//This method adds shared adbannerview to the current view and sets its location to bottom of screen
//Should work on all devices
-(void) addADBannerViewToBottom
{
    SharedAdBannerView.delegate = self;
    //Position banner just below the screen
    SharedAdBannerView.frame = CGRectMake(0, self.view.bounds.size.height, 0, 0);
    //Height will be automatically set, raise the view by its own height
    SharedAdBannerView.frame = CGRectOffset(SharedAdBannerView.frame, 0, -SharedAdBannerView.frame.size.height);
    [self.view addSubview:SharedAdBannerView];
}

-(void) removeADBannerView
{
    SharedAdBannerView.delegate = nil;
    [SharedAdBannerView removeFromSuperview];
}

@end

And now in every viewcontroller that is going to display iADs, import the category and in viewDidLoad:

- (void)viewDidLoad
{
    ...
    [self removeADBannerView];
    [self addADBannerViewToBottom];
    ...
}
guenis
  • 2,520
  • 2
  • 25
  • 37
  • I have taken on board some of your recommendation - namely - having only one AdBannerView and creating it dynamically rather than in various XIBs. There are other issues such as why this problem happens in iPad and not iPhone which I have not got a sensible explanation for yet from anyone though one of the comments talks about making the app Universal which was both helpful and annoying simultaneously! +some points for your help thank you very much. – Damo May 17 '13 at 13:01
0

To prevent the views getting messed up, try turning "Auto Layout" off.

Xcode 4.5 corrupting XIBs?

Community
  • 1
  • 1
Totoro
  • 3,398
  • 1
  • 24
  • 39
0

I have solved this problem.

The root of the problem is that iPad's view property of iPad's UIViewController looping recursively.

All you need is to break infinite call. enter image description here

In my case I just add these lines:

if (_banner.alpha == 0)
{
    return;
}

in banner hiding method.

I guess you have crash here:

hiddenFrame.origin.y = self.view.frame.size.height;

Anyway, its not a good approach do not check property before changing.

Mike Glukhov
  • 1,758
  • 19
  • 18