Admob Integration on iPhone - Memory Leak Problem - iphone

I wonder if anyone can help with the following. I have integrated both iAds and AdMob into my app. However a user reported that the app crashes on the iPod Touch. Using Instruments in xCode I have managed to identify that something called "GOOGLE_SHUFFLE_RVS_User_waylonis_Code_afma1_googlmac_iPhone_GoogleAds_Signals_Protected_build_GoogleAdsSignals_build_Release_iphoneos_Google" is causing a memory leak of about 500 bytes everytime it is called.My ad refresh rate is set at 20 seconds so this happens every 20 seconds.
My code is as follows.
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
if (self.bannerIsVisible)
{
[UIView beginAnimations:#"animateAdBannerOff" context:NULL];
// banner is visible and we move it out of the screen, due to connection issue
banner.frame = CGRectOffset(banner.frame, 0, -90);
[UIView commitAnimations];
self.bannerIsVisible = NO;
}
[self loadAdMobAd];
}
-(void)loadAdMobAd {
if (!bannerView_) {
CGRect adSize = CGRectMake (0,40,0,0);
adSize.size = GAD_SIZE_320x50;
bannerView_ = [[GADBannerView alloc] initWithFrame:adSize];
bannerView_.rootViewController = self;
bannerView_.adUnitID = MY_BANNER_UNIT_ID;
bannerView_.rootViewController = self;
[self.view addSubview:bannerView_];
// Initiate a generic request to load it with an ad.
[bannerView_ loadRequest:[GADRequest request]];
}
}
The idea is that if an iAd is not available an AdMob ad is loaded instead.
Is there anything wrong with my code that could be causing the leak ?
Many thanks,
Martin

Apparently the GOOGLE_SHUFFLE_RVS memory leak is a known issue. According to the Google Group (http://groups.google.com/group/google-admob-ads-sdk/browse_thread/thread/2631fcb87d909bfa/edafd2a4ac175f47?lnk=gst&q=memory+leak#edafd2a4ac175f47), "it's a known glitch, and it'll be fixed in the next release" (from a comment posted on March 31). They also say it's fixed internally but not released yet.
I was very surprised that AdMob/Google didn't give higher priority to something as significant as an ad banner that leaks memory every time an ad loads. I guess everyone is just using the memory leaking version for now. :-o
Joe

You're alloc'ing bannerView_, adding it to the view, but not releasing it.
Try adding [bannerView_ release]; after the loadRequest line.

Related

Application Crash due to Memory issue / MBProgressHUD Indicator

I have a strange issue .
I am currently working on a mail app and it used to crash randomly without and error or logs in my console . I checked my Crash Log it showed me Low Memory warning with jettisoned written next to my App.
So I suspect it's an memory issue and went back to trace my memory usage of my application.
I used allocation instrument to detect the overall usage and my application crashed when it's heap size was just 4.59 MB.
Instruments point towards a function where I am using MBProgressHUD indicator.
The culprit is this one line :
[appDelegate showHUDActivityIndicatorOnView:self.parentViewController.view whileExecuting:#selector(refreshInBackground) onTarget:self withObject:nil withText:#"Loading"];
If I replace this with
[self refreshInBackground] everything works fine no issues ..
Here is the code :
-(void) showHUDActivityIndicatorOnView:(UIView*)view whileExecuting:(SEL)method
onTarget:(id)target withObject:(id)object withText:(NSString*)label{
self.HUD = [[MBProgressHUD alloc] initWithView:view] ;
self.navigationController.navigationItem.hidesBackButton = YES;
[view addSubview:self.HUD];
self.HUD.delegate = nil;
self.HUD.labelText = label;
[self.HUD showWhileExecuting:method onTarget:target withObject:object animated:YES];
}
self.HUD is a property which is being retained.
With a slight modification is showWhileExecuting method as follows :
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
MyAppdelegate *appDelegate = (MyAppdelegate *)[UIApplication sharedApplication].delegate;
if(!appDelegate.isRequestActive)
{
methodForExecution = method;
targetForExecution = [target retain];
objectForExecution = [object retain];
// Launch execution in new thread
taskInProgress = YES;
[NSThread detachNewThreadSelector:#selector(launchExecution) toTarget:self withObject:nil];
// Show HUD view
[self show:animated];
}
else {
[self done];
}
}
currently I have removed this from my app and it works fine now and it does not crashes even with the usage of 20 - 30 MB heap Memory .
I am not looking for an specific answer or solution here . What I am looking for ways to debug / techniques to debug the issue so that I can get to know what caused my app to crash .
Is it memory overflow . If that's the case then how can I use 20-30 MB right now.
If it's not an memory issue why does my crash reporter shows jettisoned next to my App name .
the culprit line ([appDelegate showHUDActivityIndicatorOnView:self.parentViewController.view whileExecuting:#selector(refreshInBackground) onTarget:self withObject:nil withText:#"Loading"])
Every time when I call this function some memory increases , because of some elements being cached . But when memory reached 4.5 MB ...this line cause it to crash
How do I get to the root cause of this issue . How do I figure out why iOS is killing my app the reason for jettisoned written next to my app
Any help or suggestions would be really appreciated .
Ok. The problem is I was adding the HUD progress bar on my view using
[view addSubview:self.HUD];
I forgot to remove it from the super view in its delegate method:
- (void)hudWasHidden:(MBProgressHUD *)hud
{
// Remove HUD from screen when the HUD was hidded
[HUD removeFromSuperview]; // app crashes at 4.59 MB if you comment this
[HUD release];
HUD = nil;
}
Because of this several views were added every time on one UIView ... I guess there is an upper limit for the number of child subviews on top of each UIView .... apple should mention this in their documentation ...
If you're not using ARC, you have for sure a leak every time you assign the property:
self.HUD = [[MBProgressHUD alloc] initWithView:view] ;
Change your code in this way:
MBProgressHUD *progressHUD = [[MBProgressHUD alloc] initWithView:view] ;
self.HUD = progressHUD;
[progressHUD release];

Strange memory leak in Window:addSubView

first of all sorry for my English :-) not so good.
I have a strange memory leak with the following code (code after the explanation).
I have a class, FLWaitingView. It is a simple view with a waiting indicator (plus a view with background), used to say to the user "wait for the data to be loaded".
It has two simple methods: show and dismiss.
In the show method, I find the main Application Window and add the subviews (the waiting view and a background view, with different animations). In the dismiss method, I remove it from superview.
In every show, I verify that the view isn't already visible using a static bool var (is_visible).
The strange thing is this: In the dismiss method, I use:
[self.view removeFromSuperview];
[self.waitingView removeFromSuperview];
to remove the two views from the Window, to avoid them to be retained. They are correctly removed, I can verify this with NSLog (for cicle on each window subview). But, in INSTRUMENTS, using the "mark heap" function, I see that in every single reload (new instance of FLWaitingView, then show, then dismiss) the old instance remains in memory and continues to increase memory usage. Obviously is not a problem of the calling code, because I correctly release the object:
//CALLING CODE
//customWaitingView is a property retained
self.customWaitingView = [[[FLWaitingView alloc]init]autorelease];
[self.customWaitingView show];
Moreover, and I think that this is the most important information, if I move the view dismission in another method, called by a selector, the leak disappear!!!
Now I show the "wrong" code and, after, the "correction". I would like to understand why it happens.
- (void)show
{
if (!is_visible){
id appDelegate = [[UIApplication sharedApplication] delegate];
UIWindow *window = [appDelegate window];
self.waitingLabel.text = #"Attendere";
self.view.alpha = 1.0;
self.waitingView.alpha = 1.0;
[window addSubview:self.view];
[window addSubview:self.waitingView];
[self.waitingIndicator startAnimating];
self.view.frame = window.frame;
self.waitingView.center = window.center;
// "Pop in" animation for alert
[self doPopInAnimationWithDelegate:self];
// "Fade in" animation for background
[self doFadeInAnimation];
is_visible = YES;
} else {
NSLog(#"FLWaitingView %# already visible, do nothing", self);
}
}
- (void)dismiss
{
[UIView beginAnimations:nil context:nil];
self.view.alpha = 0.0;
self.waitingView.alpha = 0.0;
[UIView commitAnimations];
[self.waitingIndicator stopAnimating];
//here is the problem
[self.view removeFromSuperview];
[self.waitingView removeFromSuperview];
is_visible = NO;
}
the code above is the "wrong" one, but if I add
[self performSelector:#selector(alertDidFadeOut) withObject:nil afterDelay:0.5];
in the dismiss method and a new method (obviously removing the redundant code from dismiss method):
- (void)alertDidFadeOut
{
//here the memory is correctly released
[self.view removeFromSuperview];
[self.waitingView removeFromSuperview];
is_visible = NO;
}
the memory is correctly released.
Why??????
Thank you in advance
Fabio
Your view isn't getting released as you would be expecting because at the moment you're releasing it there are still animations linked to it. You can only properly release it after the animations are finished.
Your second method works because the animation lasts less than 0.5 seconds - the releasing code is called after view is freed of all the animations.
Proper way to animate the view would be to either create an animation and assign its delegate or maybe a bit more elegant soulution is to use block-based animation like this:
- (void)dismiss
{
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[UIView animateWithDuration: 0.15
animations: ^{
self.view.alpha = 0.0;
self.waitingView.alpha = 0.0;
}
completion: ^(BOOL finished){
[self.waitingIndicator stopAnimating];
    [self.view removeFromSuperview];
    [self.waitingView removeFromSuperview];
    is_visible = NO;
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
}];
}

didFailToReceiveAdWithError never fires

This is my first iAd for iPhone.
In development mode, if I switch my iPhone to airport mode, my app being debugged never ever gets this event.
But, if I start app with airport off, I get the 'bannerViewDidLoadAd' event okay. And if airport turned on -- never get didFailToReceiveAdWithError.
#interface ViewController : UIViewController <ADBannerViewDelegate> {
ADBannerView* adView;
}
#property(nonatomic, retain) IBOutlet ADBannerView *adView;
...
- (void)viewDidLoad
{
... (adView is from Interface Builder )
adView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifier320x50];
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifier320x50;
[self.view addSubview:adView];
adView.delegate=self;
[super viewDidLoad];
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
NSLog(#"bannerViewDidLoadAd");
if ( adView.hidden )
{
NSLog(#"going visible");
[UIView beginAnimations:#"animateAdBannerOn" context:NULL];
adView.hidden = NO;
// banner is invisible now and moved out of the screen on 50 px
//banner.frame = CGRectOffset(banner.frame, 0, 50);
[UIView commitAnimations];
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(#"didFailToReceiveAdWithError");
if( !adView.hidden ) // ad banner displayed, but lost ad network
{
NSLog(#"going hidden");
[UIView beginAnimations:#"animateAdBannerOff" context:NULL];
adView.hidden = YES;
// banner is visible and we move it out of the screen, due to connection issue
//banner.frame = CGRectOffset(banner.frame, 0, -50);
[UIView commitAnimations];
}
}
The only time
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
is called is when an ad is already displayed and receives an error. When you are in airplane mode the initial ad is never displayed therefore this method is not called.
*Edit for clarity
If you check the Apple Developer Documentation you notice you have 2 options:
To assist you in validating your implementation, the iAd Network
occasionally returns errors to test your error handling code.
You can also test your error handling support manually by turning your device’s wireless capability off.
http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/iAd_Guide/TestingiAdApplications/TestingiAdApplications.html#//apple_ref/doc/uid/TP40009881-CH6-SW1
Take into account that you can't turn off wireless for the iOS simulator. You need to disable the network connection of your development system:
IPhone Connectivity Testing: How do I force it to lose connection?

Why is my AdMob code leaking in my iphone app?

I have included AdMob in my iphone app. I have the following code in my viewDidLoad method:
bannerView_ = [[GADBannerView alloc]
initWithFrame:CGRectMake(0.0,
0.0,
320,
50)];
// Specify the ad's "unit identifier." This is your AdMob Publisher ID.
bannerView_.adUnitID = ADMOB_BANNER_UNIT_ID;
// Let the runtime know which UIViewController to restore after taking
// the user wherever the ad goes and add it to the view hierarchy.
bannerView_.rootViewController = self;
[self.view addSubview:bannerView_];
// Initiate a generic request to load it with an ad.
GADRequest *r = [[GADRequest alloc] init];
r.testing = YES;
[bannerView_ loadRequest:r];
[r release];
This leaks. When I comment out the second last line ( [bannerView_ loadRequest:r]; ), the leak disappears. The only thing I changed in this code from the example provided by Google was to introduce the variable r so I could put AdMob in testing mode. In the code supplied by Google, bannerView_ is released by viewDidUnload. I looked for the loadRequest method but all I found was a definition in the GADBannerView.h file. As far as I can tell, there is no GADBannerView.m file, which seems weird in itself. Anyway, any tips would be much appreciated.
Thanks,
John
Why don't you use this AdMediator - it is very simple to configure and you don't have to worry about AdMob and iAds (if you want to use it) :
will swap in AdMob ads if no iAds are
available.
Are you releasing bannerView_ in your dealloc method or somewhere else appropriate ?
Instead of:
GADRequest *r = [[GADRequest alloc] init];
You could try:
GADRequest *r = [GADRequest request];

AdMob not showing ads in iOS simulator

I am trying to use AdMob on an app (built for iOS 4.0)
I've added the sample code available in the tutorial http://code.google.com/mobile/ads/docs/ios/fundamentals.html which is the following (I've changed the adUnitID):
// Create a view of the standard size at the bottom of the screen.
bannerView_ = [[GADBannerView alloc]
initWithFrame:CGRectMake(0.0,
self.view.frame.size.height -
GAD_SIZE_320x50.height,
GAD_SIZE_320x50.width,
GAD_SIZE_320x50.height)];
// Specify the ad's "unit identifier." This is your AdMob Publisher ID.
bannerView_.adUnitID = #"XYZ";
// Let the runtime know which UIViewController to restore after taking
// the user wherever the ad goes and add it to the view hierarchy.
bannerView_.rootViewController = self;
[self.view addSubview:bannerView_];
[self.view bringSubviewToFront:bannerView_];
GADRequest * request = [GADRequest request];
// Initiate a generic request to load it with an ad.
[bannerView_ loadRequest:request];
Doing this nothing happens, no ad is shown and the number of requests in my AdMob app page increase erratically (i.e.: I can't seem to notice a pattern), but the most important is no ad is shown.
If I add the following code:
GADRequest * request = [GADRequest request];
request.testDevices = [NSArray arrayWithObjects:
GAD_SIMULATOR_ID, // Simulator
nil];
// Initiate a generic request to load it with an ad.
[bannerView_ loadRequest:request];
I get the "Success! You are now ready to travel through the App Galaxy" default banner, but only this one.
So my questions are:
Aren't the sample code enough to show ads? Why I never see an ad with the sample code?
As far as I understood, requests mean the number of times my app asked for an ad to be shown. I also understood that not every request is replied with an ad (otherwise the fill rate would be 100%), but still, I NEVER saw an ad, what am I doing wrong?
Thanks in advance.
GADBannerView *bannerView = [[GADBannerView alloc]
initWithFrame:CGRectMake(0.0,
self.view.frame.size.height -
GAD_SIZE_320x50.height,
GAD_SIZE_320x50.width,
GAD_SIZE_320x50.height)];//Set Position
bannerView.adUnitID = #"12331255421245";//Call your id
// Let the runtime know which UIViewController to restore after taking
// the user wherever the ad goes and add it to the view hierarchy.
bannerView.rootViewController = self;
[self.view addSubview:bannerView];//Your attempt to add bannerview
// Initiate a generic request to load it with an ad.
[bannerView loadRequest:[GADRequest request]];
I set all above methods. Ad banner looks properly in Device but not showing ad in Simulator.
I set device Id as GAD_SIMULATOR_ID.but it doesnt work. Its delegate methods are not being called. !!
Try it in the device. Apps in simulator don't show Admob ads.