iAd doesn't hide when it fails to load? - iphone

This seems like the dumbest question ever, but after wading through all of Apple's documentation and the useless online tutorials, I still can't figure out how to properly implement iAds into my application. So, my app starts off in a table view controller, and I have an iAd object underneath the navigation bar and above the table.
Now, in my code: (I also have the iAd framework added)
#import <UIKit/UIKit.h>
#import <iAd/iAd.h>
#interface MasterTableViewController : UITableViewController <ADBannerViewDelegate>
{
IBOutlet ADBannerView *iAd;
}
#property(nonatomic, readonly, getter=isBannerLoaded) BOOL bannerLoaded;
#end
then in the .m file
#import "MasterTableViewController.h"
#interface MasterTableViewController ()
#end
#implementation MasterTableViewController
#synthesize bannerLoaded;
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
if (!willLeave)
{
// nothing in this case thanks to ARC
}
return YES;
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
iAd.hidden = NO;
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
iAd.hidden = YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
for (int i = 0; i > 0; i++)
{
if (bannerLoaded)
{
iAd.hidden = NO;
}
else
{
iAd.hidden = YES;
}
}
}
Now, the problem is, when I test the app without internet connection the iAd does not load (obviously) BUT it also does not hide. So, at the top of the screen I'm left with a big white rectangle. Otherwise, the ad works fine when a connection is available. Does anyone have any ideas? Also - I just added the endless loops to see if they made a difference, those were completely on purpose lol.

I'm assuming you have added your ADBannerView via the Storyboard as I can't see where you initialise the banner position.
In storyboard, set the initial location just off screen.
In "bannerViewDidLoadAd", animate the banner into view.
In "bannerView: didFailToReceiveAdWithError:", animate the banner out of view.
There is a good example here https://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/iAd_Guide/WorkingwithBannerViews/WorkingwithBannerViews.html
Hope this helps. I have just implemented this but don't have access to my code at the moment.
It does bring up some errors in the simulator but works fine on a device.
I have tested this on iOS6 and works ok even if an iAd is displayed then the user loses the connection (so it looks like "bannerView: didFailToReceiveAdWithError:" is being called for me).

You have a property bannerLoaded for saving the state of your Ad, which is good.
At the very first, in your viewDidLoad method, iAd can't be loaded, so you have to set your property accordingly : self.bannerLoaded = NO;
Then, when you receive / fail to receive your ad, you need to update this property.
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
if (!self.bannerLoaded) {
iAd.hidden = NO;
self.bannerLoaded = YES;
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
if (self.bannerLoaded) {
iAd.hidden = YES;
self.bannerLoaded = NO;
}
}

Related

iAd not showing banner ads

I am building an app in which I want to us iAd banners. the viewcontroller in which I want to show the ad is a UIViewController. I am using storyboards. I implemented the iAd banner exactly as apple shows/demonstrates here:
add iAd framework
import "<iAd/iAd.h>" header
inserted self.canDisplayBannerAds = YES;
but when I run my app, no iAd is showing up. do I forget something? Thank you so much in advance
I had a bit different issue, but the answer fits to your question as well. I updated my old xib file (was from XCode 5.1) to use Size Classes in XCode 6.0. After the update ads showed only in iPhone 4 - 5 and 5s. iPhone 6 and iPhone 6 Plus was without banners (simulators showed the same results as the external devices). When using xib file and using
self.canDisplayBannerAds = YES;
in my situation I moved this command from viewDidLoad to viewDidAppear and banner showed up. Now I can see banners in all devices.
In your .h :
#interface MyViewController : UIViewController <ADBannerViewDelegate>
Add a banner view in your xib file and link this banner view with an IBOutlet
#property (nonatomic, strong) IBOutlet ADBannerView *iAdBannerView;
add the following code to display your ad :
#pragma mark - ADBannerViewDelegate
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
NSLog(#"banner loaded");
// Display BannerView
_iAdBannerView.hidden = NO;
[UIView animateWithDuration:0.4f
animations:^{
_iAdBannerView.alpha = 1.0f;
}];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
// Print error
NSLog(#"error banner failed :\n%#", error);
// Hide BannerView
[UIView animateWithDuration:0.4f
animations:^{
_iAdBannerView.alpha = 0.0f;
} completion:^(BOOL finished) {
_iAdBannerView.hidden = YES;
}];
}
and normally your adbanner will appear when you receive and ad and disappear otherwise.
The problem was that I had to sign the iAd contract in itunes connect, which I had not done yet. it works fine now!

UIImagePickerControllerCameraDeviceFront works every other time

This question is very similar to an existing question asked here UIImagePickerControllerCameraDeviceFront only works every other time I tried the solution presented but it didn't work for me
I have a simplest of a project with two view controllers. In the blue one I am displaying a small UIView with a UIImagePickerController in it. NOTE: I am displaying front facing camera when app is launched.
I hit the next button and go to orange view controller and when I hit the back button and come back to blue view controller the UIImagePickerController flips from Front to rear. I guess the reason is that it thinks its busy and moves to the rear cam. If I keep moving back and forth between the view controllers the camera keeps flipping front, back, front, back, front, back...
Here is my code and screenshots, what am I doing wrong?
In my *.h
#import <UIKit/UIKit.h>
#interface v1ViewController : UIViewController <UIImagePickerControllerDelegate>
{
UIImagePickerController *picpicker;
UIView *controllerView;
}
#property (nonatomic, retain) UIImagePickerController *picpicker;
#property (nonatomic, retain) UIView *controllerView;
#end
In my *.m file (This code is only used when blue colored view controller is displayed)
#import "v1ViewController.h"
#import <MobileCoreServices/UTCoreTypes.h>
#implementation v1ViewController
#synthesize picpicker;
#synthesize controllerView;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
picpicker = [[UIImagePickerController alloc] init];
picpicker.delegate = self;
picpicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeImage, nil];
picpicker.sourceType = UIImagePickerControllerSourceTypeCamera;
picpicker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
picpicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
picpicker.showsCameraControls = NO;
picpicker.navigationBarHidden = NO;
picpicker.wantsFullScreenLayout = NO;
controllerView = picpicker.view;
[controllerView setFrame:CGRectMake(35, 31, 250, 250)];
controllerView.alpha = 0.0;
controllerView.transform = CGAffineTransformMakeScale(1.0, 1.0);
[self.view addSubview:controllerView];
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
controllerView.alpha = 1.0;
}
completion:nil
];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[picpicker dismissModalViewControllerAnimated:YES];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[picpicker dismissModalViewControllerAnimated:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
You are dismissing the controller in both the viewDidDisappear and viewWillDisappear methods.
That could be the cause of your problem.
Although I do not have a device with a camera available right now to verify this, it seems that you're not dismissing the pickerview controller correctly. The documentation states that you should call dismissModalViewControllerAnimated: on the parent controller in order to dismiss the picker (though, calls to presented controllers will propagate to presenters - so this is not the problem), but in your case you're not displaying the controller modally in the first place so it will not work.
What I would try in this case is to release the picker instead (if not under ARC) and set it to nil (instead of calling [picpicker dismissModalViewControllerAnimated:YES];).
PS. In fact, it seems that there is a bigger problem with your design. Since each button is set to present the other party modally you are not dismissing any of the controllers ever. The controllers just keep stacking on each other. You should either consider to embed them in a navigation controller and have it handle the hierarchy or just set dismissModalViewControllerAnimated: (dismissViewControllerAnimated:completion: on iOS5+) as the action of the second controller's button instead of a modal segue.
This is a very simple issue. I don't know why this happens exactly, but it seems that UIImagePickerController was designed to recreated each time it's needed instead of keeping any reference to it, which seems logical if you think about it. Basically, you need to recreate and reconfigure your picker each time. Below I've pasted some code to give an image of what I mean.
Simple solution:
- (UIImagePickerController *)loadImagePicker {
UIImagePickerController *picpicker = [[UIImagePickerController alloc] init];
picpicker.delegate = self;
picpicker.mediaTypes = [NSArray arrayWithObjects:(NSString *)kUTTypeImage, nil];
picpicker.sourceType = UIImagePickerControllerSourceTypeCamera;
picpicker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
picpicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
picpicker.showsCameraControls = NO;
picpicker.navigationBarHidden = NO;
picpicker.wantsFullScreenLayout = NO;
return picpicker;
}
and in:
-(void)viewWillAppear:(BOOL)animated{
if(!self.picpicker){
self.picpicker = [self loadImagePicker];
[self.view addSubview: self.picpicker];
}
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.picpicker removeFromSuperview];
self.picpicker = nil;
}

iAd & Admob integration

I integrated iAd / Admob display code from the link from here: http://www.apptite.be/tutorial_mixing_ads.php
and had some weird results. On admob, my click through rate dropped 40%, but the number of impressions stayed the same. Its as if both ads are shown at the same time, with iAds on top of admob ads. Does anyone see problems with the code on that site that could possibly cause that?
Thank you in advance for your help.
Firstly we should download Admob Sdk from google.
That file is required In google AdMob API :-
GADAdSize.h
GADBannerView.h
GADBannerViewDelegate.h
GADInterstitial.h
GADInterstitial.h
GADRequest.h
GADRequestError.h
libGoogleAdMobAds
#import <UIKit/UIKit.h>
#import "GADBannerViewDelegate.h"
#class GADBannerView, GADRequest;
#interface BannerExampleViewController : UIViewController
<GADBannerViewDelegate> {
GADBannerView *adBanner_;
}
#property (nonatomic, retain) GADBannerView *adBanner;
- (GADRequest *)createRequest;
#end
#import "BannerViewController.h"
#import "GADBannerView.h"
#import "GADRequest.h"
#implementation BannerExampleViewController
#synthesize adBanner = adBanner_;
#pragma mark init/dealloc
// Implement viewDidLoad to do additional setup after loading the view,
// typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
CGPoint origin = CGPointMake(0.0,
self.view.frame.size.height -
CGSizeFromGADAdSize(kGADAdSizeBanner).height);
self.adBanner = [[[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner
origin:origin]
autorelease];
self.adBanner.adUnitID = AdMob key;
self.adBanner.delegate = self;
[self.adBanner setRootViewController:self];
[self.view addSubview:self.adBanner];
[self.adBanner loadRequest:[self createRequest]];
}
- (void)dealloc {
adBanner_.delegate = nil;
[adBanner_ release];
[super dealloc];
}
#pragma mark GADRequest generation
- (GADRequest *)createRequest {
GADRequest *request = [GADRequest request];
request.testing = YES;
return request;
}
#pragma mark GADBannerViewDelegate impl
- (void)adViewDidReceiveAd:(GADBannerView *)adView {
NSLog(#"Received ad successfully");
}
- (void)adView:(GADBannerView *)view
didFailToReceiveAdWithError:(GADRequestError *)error {
NSLog(#"Failed to receive ad with error: %#", [error localizedFailureReason]);
}
#end
Hmm, so I'm looking at the code that says:
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(#"iAdBanner failed");
// Only request adMob when iAd did fail
[self adMobRequest];
And on Apple's site, it says that "Even after an error is sent to your delegate, the banner view continues to try to download new advertisements. Thus, implementing both of these delegate methods allows your application to display the banner only when advertisements are loaded." (link)
I'm guessing that what is happening is that if iAd fails, you're displaying an AdMob ad, but then iAd is also retrying as well and so if it fails again, it is requesting another AdMob ad despite the fact that one may already be getting shown?

How do I update the screen before applicationDidBecomeActive?

I need to hide something on the screen when the user has activates the application by switching it to the foreground.
I have tried inserting my code within applicationDidBecomeActive or applicationWillEnterForeground and although it runs OK the old screen with the text I want to hide is displayed momentarily.
How can I hide the field before the screen is redrawn?
Thanks
iphaaw
I think the problem is, iOS will capture a screenshot from your app in the moment it goes to the background, so the animation will work in an instant.
The only way in my opinion to do this is to hide / cover your view in moment the app goes to the background.
Write some code in applicationWillResignActive: to 'hide' whatever you need to hide.
I faced a similar situation but, instead of hiding, I wanted to show a block code screen to grant access. Anyway I think that the solution also applies to your needs.
I often implement a custom base view controller in my iOS applications. So instead of dealing with applicationDidBecomeActive: or applicationWillResignActive: I setup this view controller to listen for the equivalent notifications:
#interface BaseViewController : UIViewController
- (void)prepareForGrantingAccessWithNotification:(NSNotification *)notification;
- (void)grantAccessWithNotification:(NSNotification *)notification;
#end
#implementation BaseViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self addNotificationHandler:#selector(grantAccessWithNotification:)
forNotification:UIApplicationDidBecomeActiveNotification];
[self addNotificationHandler:#selector(prepareForGrantingAccessWithNotification:)
forNotification:UIApplicationWillResignActiveNotification];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)prepareForGrantingAccessWithNotification:(NSNotification *)notification {
// Hide your views here
myCustomView.alpha = 0;
// Or in my case, hide everything on the screen
self.view.alpha = 0;
self.navigationController.navigationBar.alpha = 0;
}
- (void)grantAccessWithNotification:(NSNotification *)notification {
// This is only necessary in my case
[self presentBlockCodeScreen];
self.view.alpha = 1;
self.navigationController.navigationBar.alpha = 1;
...
}
#end

frame size does not change in landscape mode

I have a UINavigationController that can rotate to landscape mode and that it initializes a new UIViewController and pushes it on the stack. On the UIViewController's viewDidLoad I just print the self.view.frame.size.
If the UINavigationController is in Portrait mode, the View Controller will print {320, 460}. However, when the Navigation Controller is in Landscape, the frame size is exactly the same. (To clarify, in the second case the UIViewController is initialized while the phone is already in landscape mode.)
Shouldn't the frame size of the view be rotated? And if not how I can I find the correct frame size without hardcoding the numbers?
You can't rely on the frame in landscape mode; you have to use a combination of bounds and center; frame is generated using a combination of those, and when there's a non-identity transform applied (as there is in landscape), it gets a little weird.
first you need to set your view to resize automatically with a proper autoresizingMask.
with this your view will adapt to the size of the controller itself.
you can check this yourself with an NSLog. But don't put it in loadView, this is too early. Put this in viewWillAppear.
If you set the autoresizingMask of your view with Interface Builder you should turn off the Simulated Interface Elements in the Attributes inspector. If any of these is on you can't change the autoresizingMask in the Size inspector.
This is a pain and it's still true in iOS 4.2 for iPads. The way I solved this is to subclass the UIView associated with the UIViewController. I did this in interface builder but I suppose one could also do this in code somehow. In interface builder select the UIView in the UIViewController then hit the (i) icon in the upper right of the Inspector window. Under class identity hit the popup and chose the UIView subclass below.
The approach is that this UIView subclass overrides the layoutSubviews method, finds the next UIViewController, determines if it implements a reactToLayout method (which is a method that you have to implement in the UIViewController subclass for the view controller of this view). If the reactToLayout method exists in the first UIViewController found, it is invoked.
The reactToLayout method in the view controller then does whatever one needs to do which it will be able to do successfully since the view's frame is set up properly by this time (unlike in ViewDidLoad, viewWillAppear, or even viewDidAppear). I have a method that I call anytime the orientation or frame changes. It's a pain but I store the last frame laid out and last orientation laid out in internal variables of the view controller. The internal layout for new orientation or frame change method compares these to the view's current frame and requested or current orientation so that it doesn't unnecessarily layout stuff over and over.
Here's the code:
UILayoutSubviewsView.h
#import <UIKit/UIKit.h>
#interface UILayoutSubviewsView : UIView {
}
#end
UILayoutSubviewsView.m
#import "UILayoutSubviewsView.h"
// Create this to avoid a warning that this method does not exist for UIViewControllers
// this is OK since we check to see that it does exist before invoking it
#interface UIViewController(UndocumentedMethodForUIViewController)
-(void) reactToLayout;
#end
#implementation UILayoutSubviewsView
// Pass this up to our view controller if it supports the reactToLayout method
// (this is the whole reason for the class)
-(void) layoutSubviews {
[super layoutSubviews];
// Look for the first next responder that is a UIViewController
UIViewController *ourViewController = nil;
id myNextResponder = [self nextResponder];
while (myNextResponder != nil && ourViewController == nil) {
if ([myNextResponder isKindOfClass:[UIViewController class]]) {
ourViewController = myNextResponder;
}
else {
myNextResponder = [myNextResponder nextResponder];
}
}
// If we got a view controller, then see if it supports the reactToLayout method
if (ourViewController != nil) {
if ([ourViewController respondsToSelector:#selector(reactToLayout)]) {
// Invoke the view controller's reactToLayout method
[ourViewController reactToLayout];
}
}
}
#end
YourViewController.h
#import <UIKit/UIKit.h>
#interface YourViewController : UIViewController {
CGRect lastLayedOutFrame;
UIInterfaceOrientation lastLayedOutOrientation;
}
#pragma mark -
#pragma mark Instance Methods
-(id) init;
-(void) reactToLayout;
#end
YourViewController.m
#import "YourViewController.m"
#pragma mark Private Interface Category
#interface YourViewController()
-(void) setViewForCurrentFrameAndRequestedOrientation:(UIInterfaceOrientation) interfaceOrientation;
#end
#implementation YourPadViewController
-(id) init {
// First our super then set ourselves up
if (self = [super initWithNibName:#"YourViewController" bundle:nil]) {
// Initialize some basic stuff
lastLayedOutFrame = CGRectZero;
lastLayedOutOrientation = UIDeviceOrientationUnknown;
}
return self;
}
-(void) viewWillAppear:(BOOL) animated {
[super viewWillAppear:animated];
// Make sure we're showing the right stuff in the right place
[self setViewForCurrentFrameAndRequestedOrientation:UIDeviceOrientationUnknown];
}
-(void) viewDidAppear:(BOOL) animated {
[super viewDidAppear:animated];
// Make sure we're showing the right stuff in the right place
[self setViewForCurrentFrameAndRequestedOrientation:UIDeviceOrientationUnknown];
}
-(void) reactToLayout {
// Make sure we're showing the right stuff in the right place
[self setViewForCurrentFrameAndRequestedOrientation:UIDeviceOrientationUnknown];
}
#pragma mark -
#pragma mark Rotation Support
-(BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation {
return YES;
}
// This is called right before the actual rotation
-(void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation duration:(NSTimeInterval) duration {
[super willAnimateRotationToInterfaceOrientation:interfaceOrientation duration:duration];
// Make sure we're showing the right stuff in the right place
[self setViewForCurrentFrameAndRequestedOrientation:interfaceOrientation];
}
// Make the necessary adjustments for the different view orientations
-(void) setViewForCurrentFrameAndRequestedOrientation:(UIInterfaceOrientation) interfaceOrientation {
// Set up the requested orientation (need this to handle the Unknown case)
UIInterfaceOrientation requestedOrientation;
if (interfaceOrientation != UIDeviceOrientationUnknown) {
requestedOrientation = interfaceOrientation;
}
else {
requestedOrientation = [[UIDevice currentDevice] orientation];
}
// See if we have anything to do
if (!(CGRectEqualToRect(self.view.frame, lastLayedOutFrame) && lastLayedOutOrientation == requestedOrientation)) {
// Do whatever needs to be done
// Record our last layed out frame and orientation
lastLayedOutFrame = self.view.frame;
lastLayedOutOrientation = requestedOrientation;
}
}
Hi every one
I think there is a simple solution that do the job for me
you can use currentSize instead of self.view.frame.size
in yourClass.h
#interface yourClass : UIViewController {
CGSize currentSize;
}
#property (nonatomic, readwrite)CGSize currentSize;
#end
in yourClass.m
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (toInterfaceOrientation != self.interfaceOrientation) {
CGSize newSize;
// 20 is the status bar height
newSize.width = self.view.bounds.size.height + 20;
newSize.height = self.view.bounds.size.width - 20;
currentSize = newSize;
//any other necessary code
}
}