简体   繁体   中英

iAd AdBanner Memory leak issue (App crashes)

I have a simple app with list/detail view. In the detail view, I have 1 webview and also show 1 iAd. As I toggle between list/detail view, my app crashes sometimes. It seems there is something wrong with my iAd code. Please hlp me fix it. I tried using Leaks, but am unable to figure it out completely.

Below is the UPDATED code;

@interface DetailController : UIViewController <UIWebViewDelegate,ADBannerViewDelegate> {
    NSString *selectedTxt;
    IBOutlet UIWebView* webView;
    ADBannerView *adView_;
    BOOL bannerIsVisible;
}

@property(nonatomic,retain) NSString *selectedTxt;

@property(nonatomic,retain) UIWebView* webView;

@property (nonatomic,retain) ADBannerView *adView;
@property (nonatomic,assign) BOOL bannerIsVisible;

@end

Implementation

@implementation DetailController

@synthesize selectedTxt;
@synthesize webView,bannerIsVisible;
@synthesize adView = adView_;

/*
 // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
        // Custom initialization
    }
    return self;
}
*/

- (void) viewWillAppear:(BOOL)animated {

    bannerIsVisible = YES;
    adView_ = [[ADBannerView alloc] initWithFrame:CGRectZero];

    float origin_y;
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) 
        origin_y = 360.0;
    else
        origin_y = self.view.frame.size.height;

    adView_.frame = CGRectMake(0.0,origin_y, adView_.frame.size.width, adView_.frame.size.height);

    if ( &ADBannerContentSizeIdentifierPortrait != NULL ) {
        adView_.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifierPortrait];
        adView_.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
    } else {
        adView_.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifier320x50];
        adView_.currentContentSizeIdentifier = ADBannerContentSizeIdentifier320x50;
    }

    adView_.delegate = self;

    [webView addSubview:adView_];

    [self.view bringSubviewToFront:adView_];
    self.bannerIsVisible=NO;

    [super viewWillAppear: animated];
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {

    //Set the title of the navigation bar
    //self.navigationItem.title = @"Selected Country";
    [super viewDidLoad];
}

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return YES;
}
*/

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    adView_.delegate = nil;
    self.adView = nil;
}


- (void)dealloc {
    adView_.delegate = nil;
    [adView_ release];
    [super dealloc];
}



- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
    if (bannerIsVisible)
    {
        [UIView beginAnimations:@"animateAdBannerOff" context:NULL];
        // assumes the banner view is at the bottom of the screen.
        banner.frame = CGRectOffset(banner.frame, 0, 50); // if the banner is on top of the screen use -50
        [UIView commitAnimations];
        bannerIsVisible = NO;
    }
}

- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
    if (!bannerIsVisible)
    {
        [UIView beginAnimations:@"animateAdBannerOn" context:NULL];
        // assumes the banner view is offset -50 pixels so that it is not visible.
        banner.frame = CGRectOffset(banner.frame, 0, -50); // if the banner is on top of the screen use 50
        [UIView commitAnimations];
        bannerIsVisible = YES;
    }
}

- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
    NSLog(@"Banner view is beginning an ad action");
    BOOL shouldExecuteAction = YES; // your application implements this method if you want it not fixed
    if (!willLeave && shouldExecuteAction)
    {
        // insert code here to suspend any services that might conflict with the advertisement
    }
    return shouldExecuteAction;
}



@end

Error Log

2011-12-17 20:33:23.142 MyApp[4382:207] ADBannerView: WARNING A banner view (0x6236190) has an ad but may be obscured. This message is only printed once per banner view.
[Switching to process 4382 thread 0x920f]
2011-12-17 20:34:14.154 MyApp[4382:207] -[__NSCFType bannerViewDidLoadAd:]: unrecognized selector sent to instance 0x62542f0
2011-12-17 20:34:14.195 MyApp[4382:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType bannerViewDidLoadAd:]: unrecognized selector sent to instance 0x62542f0'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00e025a9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x00f56313 objc_exception_throw + 44
    2   CoreFoundation                      0x00e040bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
    3   CoreFoundation                      0x00d73966 ___forwarding___ + 966
    4   CoreFoundation                      0x00d73522 _CF_forwarding_prep_0 + 50
    5   CoreFoundation                      0x00d72c7d __invoking___ + 29
    6   CoreFoundation                      0x00d72b51 -[NSInvocation invoke] + 145
    7   CoreFoundation                      0x00d73a04 ___forwarding___ + 1124
    8   CoreFoundation                      0x00d73522 _CF_forwarding_prep_0 + 50
    9   iAd                                 0x000149f9 -[ADDistributedMessagingCenter messagePort:receivedMessage:withData:] + 251
    10  iAd                                 0x00015012 ADMessagePortCallBack + 75
    11  CoreFoundation                      0x00db9f4c __CFMessagePortPerform + 396
    12  CoreFoundation                      0x00de3944 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
    13  CoreFoundation                      0x00d43cf7 __CFRunLoopDoSource1 + 215
    14  CoreFoundation                      0x00d40f83 __CFRunLoopRun + 979
    15  CoreFoundation                      0x00d40840 CFRunLoopRunSpecific + 208
    16  CoreFoundation                      0x00d40761 CFRunLoopRunInMode + 97
    17  GraphicsServices                    0x033ff1c4 GSEventRunModal + 217
    18  GraphicsServices                    0x033ff289 GSEventRun + 115
    19  UIKit                               0x00300c93 UIApplicationMain + 1160
    20  MyApp                     0x00002440 main + 102
    21  MyApp                     0x000023d1 start + 53
)
terminate called after throwing an instance of 'NSException'
[Switching to process 4382 thread 0x207]

You are not releasing your iAd instance.

  1. Add an instance variable for the iAd
  2. Make sure its delegate is set to nil when unloading the view.
  3. Make sure it is released when unloading the view

Within you DetailController interface declaration (.h);

@interface DetailController ...
{
    ...
    //note, we are using an instance variable with the trailing underscore
    ADBannerView *adView_;
}
//note, we are using an accessor without that trailing underscore - those are 
//glued together using the synthesize mechanics within the implementation
@property (nonatomic,retain) ADBannerView *adView;
...
@end

Within you DetailController implementation (.m);

@implementation DetailController

//this will glue the instance variable with our property accessor
@sythesize adView = adView_;
...

-(void)viewDidLoad
{
     [super viewDidLoad];
     //retained by alloc/init, hence no need for using the retain by the accessor
     adView_ = [[ADBannerView alloc] initWithFrame:CGRectZero];

     //note, in case you want this adbanner to be initialized at a different point,
     //like for example in viewWillAppear that you have to consider its former instance.
     //to be on the safe side, you could prefix the above init with a [adView release];
     ...
}

-(void)viewDidUnload
{
    [super viewDidUnload];
    //as always, make sure the delegate is invalidated
    adView_.delegate = nil;
    //use accessor mechanics to release and invalidate for convenience
    self.adView = nil;
}

-(void)dealloc
{
    //to be on the safe side, make sure the adview is released even if 
    //viewDidUnload was not called 
    //e.g. nested viewControllers omitting viewDidUnload pass on

    //as always, make sure the delegate is invalidated
    adView_.delegate = nil;
    //do NOT use accessor mechanics within init or dealloc for safety reasons
    [adView_ release];
    [super dealloc];
}
@end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM