I want to add GADInterstitial to my iOS game, so everytime the app become active I want to present interestitial. In my AppDelegate.m, in method applicationDidBecomeActive: i call my method
-(void)splashInterstitial{
interestitial = [[GADInterstitial alloc] init];
interestitial.adUnitID = ADMOB_ID;
interestitial.delegate = self;
[interestitial loadAndDisplayRequest:[self createRequest] usingWindow:self.window initialImage:nil];
}
But everytime i close the ad i get warning:
attempt to dismiss modal view controller whose view does not currently appear. self = <GADInterstitialAppController: 0x5d3ed0> modalViewController = <GADWebAppViewController: 0x5d1ca0>
Does anyone got that warning?
I found a solution. Just always check will your initialization and visualization of banner after
viewDidAppear
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
hasLoaded = YES;
[self splashInterstitial];
}
Related
I'm attempting to show a GADInterstitial ad when a user of my app clicks a certain button to go to a certain ViewController. In the new ViewController's viewDidLoad method I check to see if the GADInterstitial ad is ready, and if it is I attempt to present it. The problem is, when I dismiss the ad I notice that the ViewController that presented the ad is no longer there and instead it has sent me back to the ViewController that launched the ViewController that presented the ad.
Here's my code:
- (void)viewDidLoad {
[super viewDidLoad];
BTRInterstitialHelper *helper = [BTRInterstitialHelper sharedHelper];
if([helper isInterstitialReady]) {
[helper.interstitial presentFromRootViewController:self];
}
My helper method just looks like this:
-(BOOL)isInterstitialReady {
if ([self.interstitial isReady]) {
return YES;
} else {
return NO;
}
}
I do notice thought that when I present the ad, this message shows up in the logs:
Presenting view controllers on detached view controllers is discouraged BTRIndividualLocationViewController: 0x7fd63bcd9c00.
Same problem occurs if I try to present it in viewWillAppear.
What am I doing wrong here?
EDIT:
I have also tried the following, to try to pass in my app's actual rootViewController:
UINavigationController *nav=(UINavigationController *)((BTRAppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;
UIViewController *rootController=(UIViewController *)[nav.viewControllers objectAtIndex:0];
[helper.interstitial presentFromRootViewController:rootController];
Still the same result though, except that message doesn't pop up in the logs.
VC2.h
#import "GADInterstitial.h"
#import "GADInterstitialDelegate.h"
set delegate
#interface VC2 : UIViewController <GADInterstitialDelegate>
and a property
#property(nonatomic, strong) GADInterstitial *interstitial;
VC2.m
in viewdidappear
self.interstitial = [[GADInterstitial alloc] init];
self.interstitial.adUnitID = #"ca-app-pub-yourNumber";
self.interstitial.delegate = self;
GADRequest *request = [GADRequest request];
for test ads in simulator
request.testDevices = #[ GAD_SIMULATOR_ID ];
coud also add location and keywords in the request (optional)
then do request
[self.interstitial loadRequest:request];
listen to delegate
-(void)interstitialDidReceiveAd:(GADInterstitial *)ad {
if ([self.interstitial isReady]) {
[self.interstitial presentFromRootViewController:self];
}
}
If you want to show the interstitial only when pressed from a certain button use NSUserdefaults.
In VC1 when button pressed
[[NSUserDefaults standardUserDefaults] setValue:#"yes" forKey:#"showInterstitial"];
[[NSUserDefaults standardUserDefaults] synchronize];
and wrap all the code for the interstitial in VC2 in viewdidappear in:
if ([[[NSUserDefaults standardUserDefaults] valueForKey:#"showInterstitial"] isEqualToString:#"yes"]) {
}
and add to -(void)interstitialDidReceiveAd:(GADInterstitial *)ad {
[[NSUserDefaults standardUserDefaults] setValue:#"no" forKey:#"showInterstitial"];
[[NSUserDefaults standardUserDefaults] synchronize];
p.s. you could also use a Bool for NSUserdefaults of course, I do use strings caus I had some errors with Bools, but Bools would be more correct I guess
A very similar scenario for me in 2018.
My current ViewControllers look like this:
ViewController 1
-> ViewController 2 (via presentViewController:animated:completion)
-> GADOInterstitialViewController (presentFromRootViewController:)
When GADOInterstitialViewController is dismissed via rewardBasedVideoAdDidClose:, ViewController 2 is instantly dismissed also.
A simple solution to this issue that I have figured out. Simply override ViewController 2 function dismissViewControllerAnimated like this:
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
if(self.presentedViewController != nil){
[self.presentedViewController dismissViewControllerAnimated:flag completion:completion];
} else {
[super dismissViewControllerAnimated:flag completion:completion];
}
}
This code block checks if ViewController 2 has a presented view controller and dismisses it, if not then ViewController 2 gets dismissed.
This works perfectly in my case :)
I have implemented Admob into my app but i've noticed that if the Admob view doesn't receive an ad, I can't remove it from the superview. If it already has an ad loaded it just stays there with that ad loaded even if the device is not connected to the internet. This is my code:
self.admobBannerView = [[GADBannerView alloc] init];
self.admobBannerView.frame = CGRectMake(0.0,self.view.frame.size.height-50,
GAD_SIZE_320x50.width,
GAD_SIZE_320x50.height);
self.admobBannerView.adUnitID = #"...";
self.admobBannerView.rootViewController = self;
self.admobBannerView.delegate = self;
[self.view addSubview:self.admobBannerView];
[self.admobBannerView loadRequest:[GADRequest request]];
Then the Admob delegate
- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error {
[self.admobBannerView removeFromSuperview];
}
Despite calling [self.admobBannerView removeFromSuperview]; the banner remains where it is. I can't understand why this is happening. Any help is appreciated.
Thanks
I had the same problem and debugged the view hierarchy w/ Xcode only to find multiple GADBannerViews existed. Fixed the code to check if ad view already existed before adding one.
In your case you should wrap the ad view creation in:
if (self.admobBannerView != nil)
{
// create ad
}
I have a question about CvPhotoCamera (OpenCV) in the iOS App.
I have a myViewController1: in this viewController I push a mySecondView controller.
In this second View Controller I use CvPhotoCamera:
I have a UIImageViewController.
In viewDidLoad I have this code:
- (void)viewDidLoad
{
[super viewDidLoad];
_photoCamera = [[CvPhotoCamera alloc] initWithParentView:imageView];
_photoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetPhoto;
_photoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
[_photoCamera setDefaultAVCaptureDevicePosition:AVCaptureDevicePositionBack];
_photoCamera.delegate = self;
[_photoCamera start];
}
in viewDidDisappear I have this code:
- (void) viewDidDisappear:(BOOL)animated
{
[_photoCamera stop];
}
I use CvPhotoCamera to take a photo from camera using the method:
- (IBAction)actionStart:(id)sender;
{
[_photoCamera takePicture];
}
The my problem is this:
When I push this second ViewController and I tap on back button on Nav bar I have some memoryWarning and the app crashes ..always!!!
I used also the profile Xcode tool to manage memory allocation or memory leak but I do not see anything strange.
Is correct this use of CvPhotoCamera obj?
I have been developing in Objective-C for two months, so I am quite new to this language and iOS environment. I am updating to iOS7 an app that is working fine for iOS6.
I am getting the next error when a modal view with a web view inside is presented, only in iOS7 and this is working in iOS6. There is a URL request inside but I cannot find what is causing the error.
'-[__NSMallocBlock__ absoluteURL]: unrecognized selector sent to instance 0x16e8b020'
This is the viewWillAppear method on the modal view controller:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!self.webView.request) {
//THE NEXT LINE THROWS THE ERROR
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:self.initialURL];
[self.webView loadRequest:req];
}
}
Maybe I am doing something silly but really now I do not know where to look at.
If anyone has experienced something like that before, I will appreciate some help. Thanks in advance.
EDIT:
#interface MyViewController ()
#property (copy, nonatomic) NSURL *initialURL;
#end
#implementation MyViewController
- (id)initWithURL:(NSURL *)initialURL
{
self = [super init];
if (self) {
_initialURL = initialURL;
_webView = [[UIWebView alloc] init];
_webView.backgroundColor = [UIColor clearColor];
_webView.opaque = NO;
_webView.delegate = self;
[self.view addSubview:_webView];
self.modalPresentationStyle = UIModalPresentationFormSheet;
self.view.backgroundColor = [UIColor whiteColor];
}
return self;
}
Method call:
self.modalWebViewController = [[[MyViewController alloc] initWithURL:url] autorelease];
I assume that iOS calls absoluteURL on the self.initialURL object passed to the initWithURL: method. However, the object receiving this message is an NSMallocBlock, so there seems to be something wrong. I assume that your self.initialURL object should be of type NSURL. If so, this would indicate a memory management problem causing the pointer of self.initalURL to point to somewhere else in memory (not to the object you want it to point to).
You could try to run your app with NSZombiesEnabled which prevents any objects from being actually deallocated and instead warns you if a deleted object is still accessed.
You can activate NSZombies in the scheme to run your app (click on the name of your app in Xcode's toolbar on the upper right and choose "Edit Scheme..." from the pop-up menu). In the run-configuration in the "Diagnostics" tab there is a checkbox for activating Zombie objects.
I want to use AdMob in my app and I have 4 viewControllers (in 4 tab items) where I want to make it visible. The way the sample shows, every ViewController needs to make instance of it and add as subview.
I am still thinking if there can be someway to use only 1 instance that can be used in all application. How can I do that?
If I create 1 instance in AppDelegate as autorelease and retain in each viewController and on viewDidUnload release it and then in next tab item (viewController) i again retain it etc...is it good approach?
Sure, that would work but the only problem is that when you update the delegate for the ad, it will not actually pick up the new delegate for the ad unless you explicitly make a new ad request, so your old views will be receiving any notifications from the ad. I'd recommend the approach of making an adMob singleton that then forwards any delegate notifications to the right view.
So creating a class called GADMasterViewController (make sure it follows the GADBannerViewDelegate protocol too) or something which has a static initializer as so:
+(GADMasterViewController *)singleton {
static dispatch_once_t pred;
static GADMasterViewController *shared = nil;
dispatch_once(&pred, ^{
shared = [[GADMasterViewController alloc] init];
});
return shared;
}
Then in the initializer you can initialize a single GADBannerView as a property of this singleton:
-(id)init
{
if (self = [super init])
{
self.adBanner = [[GADBannerView alloc]
initWithFrame:CGRectMake(0.0,
0.0,
GAD_SIZE_320x50.width,
GAD_SIZE_320x50.height)];
// Has an ad request already been made
self.isLoaded = NO;
}
return self;
}
Then you can have a method which sets your new adView as the currentDelegate as such:
-(void)resetAdView:(UIViewController<GADBannerViewDelegate> *)rootViewController {
if (self.isLoaded) {
currentDelegate_ = rootViewController;
[rootViewController.view addSubview:self.adBanner];
}
else {
// The delegate to forward any notifications too
currentDelegate_ = rootViewController;
self.adBanner.delegate = self;
self.adBanner.rootViewController = rootViewController;
self.adBanner.adUnitID = kSampleAdUnitID;
GADRequest *request = [GADRequest request];
[self.adBanner loadRequest:request];
[rootViewController.view addSubview:self.adBanner];
self.isLoaded = YES;
}
}
At this point, you just want to forward any notifications which you get to the right viewController, so one example would be:
- (void)adViewDidReceiveAd:(GADBannerView *)view {
if ([currentDelegate_ respondsToSelector:#selector(adViewDidReceiveAd:)]) {
[currentDelegate_ adViewDidReceiveAd:view];
}
}
In ViewControllerX (one of your 4 ViewControllers), you could just add it to your view hierarchy using:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
shared = [GADMasterViewController singleton];
[shared resetAdView:self];
}
You can declare your admob view in appDelegate and add it as subview to window. Refer to admob view from VC through appDelegate
The AppDelegate aproach is a nice approach but you should not retain the instance of the admob in every viewcontroller and release the same in the viewDidUnload method. Instead of doing this just add the admob's view in every viewcontroller's viewDidLoad method as a subview. In this manner there will be only one instance of the Admob's view in the AppDelegate.
Hope this helps you.