Calling bringSubviewToFront gives error - iphone

I have been working three days straight to try and integrate ads into my iPhone game. I chose mobfox and it's been going well except a minor detail that is directly linked to my less than appropriate level of Objective-C skills.
I have everything working except that the ads get's obscured by a UI element. So I want to bring the ads to the front and googled around and managed to figure out this:
[self.view bringSubviewToFront:bannerView];
However, that only works once as the code is in (void)viewDidLoad. I then tried to use the same code in other places of my code, in the UI init etc but I then get an error that the bannerView is not declared. I pretty much understand what xcode is telling me but I don't have the skills to simply declare it and be done, I don't know how to so I ask if you can help me?
All I want to do is to bring my bannerView to front at will from anywhere in the code.
Can you help me?
Best regards
Marcus
Below is the mobfox code
The following is in viewDidLoad
// MOBFOX Starts
// create the banner view just outside of the visible area
MobFoxBannerView *bannerView = [[MobFoxBannerView alloc] initWithFrame:
CGRectMake(-800, self.view.bounds.size.height - 240, 320, 50)];
bannerView.delegate = self; // triggers ad loading
//bannerView.backgroundColor = [UIColor darkGrayColor]; // fill horizontally
bannerView.transform = CGAffineTransformMakeRotation(M_PI / 2.0); //MARCUS haxx
//bannerView.refreshAnimation = UIViewAnimationTransitionCurlDown;
[self.view addSubview:bannerView];
[self.view bringSubviewToFront:bannerView];
NSLog(#"MobFox: Ad initated and placed offscreen");
//
This is directly after viewDidLoad
//MOBFOX STARTS HERE
#pragma mark MobFox Delegate
- (NSString *)publisherIdForMobFoxBannerView:(MobFoxBannerView *)banner
{
return kMyMobFoxPublisherId;
}
- (void)mobfoxBannerViewDidLoadMobFoxAd:(MobFoxBannerView *)banner
{
NSLog(#"MobFox: did load ad and placed on screen");
// animate banner into view
//[UIView beginAnimations:#"MobFox" context:nil];
//[UIView setAnimationDuration:1];
banner.frame = CGRectMake(135, 140, 320, 50);
[UIView commitAnimations];
}
- (void)mobfoxBannerView:(MobFoxBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(#"MobFox: did fail to load ad: %#", [error localizedDescription]);
// animate banner outside view
//[UIView beginAnimations:#"MobFox" context:nil];
//[UIView setAnimationDuration:1];
banner.frame = CGRectMake(-800, self.view.bounds.size.height - 240, 320, 50);
[UIView commitAnimations];
}
//MOBFOX ENDS HERE
Example of where I would like to call bringSubViewToFront:bannerView but can't
-(void) settitleMenuToFront {
[self.view bringSubviewToFront:titleScreenImg];
[self.view bringSubviewToFront:highScoreTable];
[self.view bringSubviewToFront:ContinueButton];
[self.view bringSubviewToFront:highscoreButton];
[self.view bringSubviewToFront:newgameButton];
if (loadingScreen.alpha > 1) {
[self.view bringSubviewToFront:loadingScreen];
}
}

You need to add an instance variable, or ivar. The most straightforward way to do this is by adding a property and letting the compiler add the variable (the ivar) to store the property value.
In your header file, add a line:
#property (nonatomic, retain) MobFoxBannerView *bannerView;
In your implementation, add this line near the top:
#synthesize bannerView;
Release it in -dealloc
-(void)dealloc {
// ...
[bannerView release];
}
Then when you create the view, set the property:
self.bannerView = [[[MobFoxBannerView alloc] initWithFrame:
CGRectMake(-800, self.view.bounds.size.height - 240, 320, 50)]
autorelease];
You can then refer to self.bannerView anywhere in the rest of your code.

You need to create an instance variable that you will release and set to nil in viewDidUnload and then just release in dealloc. If using Apple's llvm 2 you can do this in a class extension otherwise add it to the header file.

Related

After launching app, how to fade in from Default.png?

When launching an iOS application, the screen jumps from the Default.png into the interface. For a current project, I'd like to fade in from that Default.png into the app's interface. Is there a good way to do this?
I took a bit of rooster117 and runmad's answers, and this is what I came up with.
Add a UIImageView to the first UIViewController's properties:
#interface DDViewController : UIViewController {
...
UIImageView *coverImageView;
}
...
#property (nonatomic, retain) UIImageView *coverImageView;
Then, for the "home screen" of the iPad app, I call the following:
- (void)viewDidLoad
{
[super viewDidLoad];
...
coverImageView = [[UIImageView alloc] init];
}
-(void)viewWillAppear:(BOOL)animated {
UIImage *defaultImage;
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
NSLog(#"Landscape!");
defaultImage = [UIImage imageNamed:#"Default-Landscape.png"];
} else {
NSLog(#"Portrait!");
defaultImage = [UIImage imageNamed:#"Default-Portrait.png"];
}
coverImageView = [[UIImageView alloc] initWithImage:defaultImage];
[self.view addSubview:coverImageView];
}
-(void)viewDidAppear:(BOOL)animated {
//Remove the coverview with an animation
[UIView animateWithDuration:1.0f animations:^(void) {
[self.coverImageView setAlpha:0.0];
} completion:^(BOOL finished){
[coverImageView removeFromSuperview];
}];
}
Yeah this isn't that hard to do. I accomplish this by making an image view with the default image and just animating it out. Something like this (put in the viewDidLoad of the first view controller):
_coverImage = [UIImage imageNamed:#"Default.png"];
}
[self.view addSubview:_coverImage];
[UIView beginAnimations:#"FadeOutCover" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(removeAndDeleteCover)];
[_coverImage setAlpha:0.0f];
[UIView commitAnimations];
then implement removeAndDeleteCover and do:
[_coverImage removeFromSuperview];
Hope that helps and if you need it to work for the iPad as a universal app you will have to check for that case and add the right default image.
Someone made a control for it on cocoacontrols.com
Here is the link for it: http://cocoacontrols.com/platforms/ios/controls/launchimagetransition
Expanding on rooster117's answer, you'll want to properly load your final "landing place", that is the view controller you want the user to actually interact with, before dismissing the "splash screen" view controller. This is very important for apps that load data from the network.
I seem to have done this in ios7 this way, think it should also work with 6 ?
https://stackoverflow.com/a/19377199/1734878

iPhone object not dying

I am using ARC in my app.
Now I faced a real problem. I need to animate two view controllers from left to right. So I just animate the the two views in button action like,
// thanks to stackoverflow for this code
test *control = [[test alloc] initWithNibName: #"test" bundle: nil];
control.view.frame = self.view.frame;
control.view.center = CGPointMake(self.view.center.x + CGRectGetWidth(self.view.frame), self.view.center.y);
[self.view.superview addSubview: control.view];
// Animate the push
[UIView beginAnimations: nil context: NULL];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: #selector(pushAnimationDidStop:finished:context:)];
control.view.center = self.view.center;
self.view.center = CGPointMake(self.view.center.x - CGRectGetWidth(self.view.frame), self.view.center.y);
[UIView commitAnimations];
- (void) pushAnimationDidStop: (NSString *) animationID finished: (NSNumber *) finished context: (void *) context
{
[self.view removeFromSuperview];
}
and in the second view controller I did the same but change the animation direction.
My real problem is when I run this code, every time I create an object of the another class and it is not deallocating. By profiling this code, found that the every time the object is alive and it is not dying and the memory allocation get increasing.
You can run the allocation instrument with reference count recording enabled. Then evaluate where the offset differs from your expectations, based on that data.

Force ADBannerView to rotate (Not "orientation" but actual transform)

this is NOT a how do I force orientation of my app question as it might look like.
My problem is probably very simple, but it is hard to describe it so here goes.
I am trying to implement iAd to my iphone game. This is not a problem, it was a 10 minute fix, just follow tutorials on the web. However, my game was programmed by a contractor since I can't program very well and he made the game translated to landscape orientation instead of oriented to landscape. This has leads to some problems for me when trying to rotate the ads correctly.
Bottom line is that CGRect which is what iAd uses does simply not have the transform function so no matter what I do the ads are standing on their side. This is quite natural since the app doesn't know that the game is meant to be played in landscape.
After a full day of research it seems that I need to put my iAd CGRect in a different view and rotate that view using the CGAffineTransformMakeRotation. My really big problem is that I am not good enough at Objective-C to actually do that.
So can you help me how I should be able to apply transform to my ad?
Code below compiles and shows the ad but standing on its side (when holding the game in landscape)
//iAD starts
// lower right:-136, 295, 320, 32 lower left:-136, 135, 320, 32 upper right:136, 295, 320, 32
// *Controller becomes a UIViewController
UIViewController *controller = [[UIViewController alloc] init];
controller.view.frame = CGRectMake(100, 100, 320, 32);
//controller.view.transform = CGAffineTransformMakeRotation(M_PI / 2.0); // turn 180 degrees
NSLog(#"*controller");
//adView becomes a CGRectZero called adView
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
//adView.frame = CGRectOffset(adView.frame, 0, 0);
adView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifierLandscape,ADBannerContentSizeIdentifierPortrait,nil];
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
[self.view addSubview:adView];
adView.delegate=self;
//self.bannerIsVisible=NO;
// iAD ends
Best regards
Marcus
This should rotate as you are asking.
This code has worked for me in my iAd apps: Directly from Apple Source Code
.h
#import <UIKit/UIKit.h>
#import <iAd/iAd.h>
#interface TextViewController : UIViewController <ADBannerViewDelegate>
{
UIView *contentView;
ADBannerView *banner;
}
#property(nonatomic, retain) IBOutlet UIView *contentView;
#property(nonatomic, retain) IBOutlet ADBannerView *banner;
#end
.m
#import ".h"
#interface TextViewController()
// Layout the Ad Banner and Content View to match the current orientation.
// The ADBannerView always animates its changes, so generally you should
// pass YES for animated, but it makes sense to pass NO in certain circumstances
// such as inside of -viewDidLoad.
-(void)layoutForCurrentOrientation:(BOOL)animated;
// A simple method that creates an ADBannerView
// Useful if you need to create the banner view in code
// such as when designing a universal binary for iPad
-(void)createADBannerView;
#end
#implementation TextViewController
#synthesize contentView, banner;
-(void)viewDidLoad{
[super viewDidLoad];
// If the banner wasn't included in the nib, create one.
if(banner == nil)
{
[self createADBannerView];
}
[self layoutForCurrentOrientation:NO];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self layoutForCurrentOrientation:NO];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[self layoutForCurrentOrientation:YES];
}
-(void)createADBannerView{
// --- WARNING ---
// If you are planning on creating banner views at runtime in order to support iOS targets that don't support the iAd framework
// then you will need to modify this method to do runtime checks for the symbols provided by the iAd framework
// and you will need to weaklink iAd.framework in your project's target settings.
// See the iPad Programming Guide, Creating a Universal Application for more information.
// http://developer.apple.com/iphone/library/documentation/general/conceptual/iPadProgrammingGuide/Introduction/Introduction.html
// --- WARNING ---
// Depending on our orientation when this method is called, we set our initial content size.
// If you only support portrait or landscape orientations, then you can remove this check and
// select either ADBannerContentSizeIdentifierPortrait (if portrait only) or ADBannerContentSizeIdentifierLandscape (if landscape only).
NSString *contentSize;
if (&ADBannerContentSizeIdentifierPortrait != nil)
{
contentSize = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifierLandscape;
}
else
{
// user the older sizes
contentSize = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? ADBannerContentSizeIdentifier320x50 : ADBannerContentSizeIdentifier480x32;
}
// Calculate the intial location for the banner.
// We want this banner to be at the bottom of the view controller, but placed
// offscreen to ensure that the user won't see the banner until its ready.
// We'll be informed when we have an ad to show because -bannerViewDidLoadAd: will be called.
CGRect frame;
frame.size = [ADBannerView sizeFromBannerContentSizeIdentifier:contentSize];
frame.origin = CGPointMake(0.0f, CGRectGetMaxY(self.view.bounds));
// Now to create and configure the banner view
ADBannerView *bannerView = [[ADBannerView alloc] initWithFrame:frame];
// Set the delegate to self, so that we are notified of ad responses.
bannerView.delegate = self;
// Set the autoresizing mask so that the banner is pinned to the bottom
bannerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
// Since we support all orientations in this view controller, support portrait and landscape content sizes.
// If you only supported landscape or portrait, you could remove the other from this set.
bannerView.requiredContentSizeIdentifiers = (&ADBannerContentSizeIdentifierPortrait != nil) ?
[NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil] :
[NSSet setWithObjects:ADBannerContentSizeIdentifier320x50, ADBannerContentSizeIdentifier480x32, nil];
// At this point the ad banner is now be visible and looking for an ad.
[self.view addSubview:bannerView];
self.banner = bannerView;
[bannerView release];
}
-(void)layoutForCurrentOrientation:(BOOL)animated{
CGFloat animationDuration = animated ? 0.2f : 0.0f;
// by default content consumes the entire view area
CGRect contentFrame = self.view.bounds;
// the banner still needs to be adjusted further, but this is a reasonable starting point
// the y value will need to be adjusted by the banner height to get the final position
CGPoint bannerOrigin = CGPointMake(CGRectGetMinX(contentFrame),CGRectGetMaxY(contentFrame));
CGFloat bannerHeight = 0.0f;
// First, setup the banner's content size and adjustment based on the current orientation
if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
banner.currentContentSizeIdentifier = (&ADBannerContentSizeIdentifierLandscape != nil) ? ADBannerContentSizeIdentifierLandscape : ADBannerContentSizeIdentifier480x32;
else
banner.currentContentSizeIdentifier = (&ADBannerContentSizeIdentifierPortrait != nil) ? ADBannerContentSizeIdentifierPortrait : ADBannerContentSizeIdentifier320x50;
bannerHeight = banner.bounds.size.height;
// Depending on if the banner has been loaded, we adjust the content frame and banner location
// to accomodate the ad being on or off screen.
// This layout is for an ad at the bottom of the view.
if(banner.bannerLoaded)
{
contentFrame.size.height -= bannerHeight;
bannerOrigin.y -= bannerHeight;
}
else
{
bannerOrigin.y += bannerHeight;
}
// And finally animate the changes, running layout for the content view if required.
[UIView animateWithDuration:animationDuration
animations:^{
contentView.frame = contentFrame;
[contentView layoutIfNeeded];
banner.frame = CGRectMake(bannerOrigin.x, bannerOrigin.y, banner.frame.size.width, banner.frame.size.height);
}];
}
-(void)viewDidUnload{
self.contentView = nil;
banner.delegate = nil;
self.banner = nil;
}
-(void)dealloc{
[contentView release]; contentView = nil;
banner.delegate = nil;
[banner release]; banner = nil;
[super dealloc];
}
#pragma mark ADBannerViewDelegate methods
-(void)bannerViewDidLoadAd:(ADBannerView *)banner{
[self layoutForCurrentOrientation:YES];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{
[self layoutForCurrentOrientation:YES];
}
-(BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave{
return YES;
}
-(void)bannerViewActionDidFinish:(ADBannerView *)banner{
}
#end
If the game is rotated, why don't you stop the rotation of the game?
I managed to do what I wanted by using a different ad SDK (mobfox) the rotation I wanted to do looks like this:
// MOBFOX Starts
// create the banner view just outside of the visible area
MobFoxBannerView *bannerView = [[MobFoxBannerView alloc] initWithFrame:
CGRectMake(-800, self.view.bounds.size.height - 240, 320, 50)];
bannerView.delegate = self; // triggers ad loading
//bannerView.backgroundColor = [UIColor darkGrayColor]; // fill horizontally
bannerView.transform = CGAffineTransformMakeRotation(M_PI / 2.0);
//bannerView.refreshAnimation = UIViewAnimationTransitionCurlDown;
[self.view addSubview:bannerView];
NSLog(#"MobFox: Ad initated and placed offscreen");
//
The transform = CGAffineTransformMakeRotation was not accepted by the iAd stuff and since I am too weak on objective-c to force it to my will. This is what I did.
Thanks for offering to help!

How to properly release a view after a UIView Animation ? :)

I have a method like the following:
- (void)add:(id)sender {
MyAddViewController *controller = nil;
controller = [[MyAddViewController alloc] initWithAddType:1];
//controller.delegate = self;
// Do some animation. Slide it in from the right side of the screen.
CGPoint initialCenter = self.view.center;
controller.view.center =
CGPointMake(initialCenter.x + 320, initialCenter.y);
// Add the subview now with it's center + 320 off the screen.
[self.view addSubview:controller.view];
[UIView beginAnimations:#"animation" context:NULL];
[UIView setAnimationDuration:0.35];
[UIView setAnimationDelegate:self];
controller.view.center = CGPointMake(initialCenter.x, initialCenter.y);
//[UIView setAnimationDidStopSelector:#selector(aMethodToBeCalledAfterAnimationEnd:finished:context:)];
[UIView commitAnimations];
//[controller release];
}
You see I have a controller release as the last line in my add method. If I uncomment this line the animation completely dies and it just dumps the view into place with no animation.
Is there a better way to do release without having to create another method which does cleanup via [UIView setAnimationDidStopSelect:#selector(aMethodToBeCalledAfterAnmiationEnd... ?
Or can I do something like setAnimationDidStopSelector:#selector([controller release]) ? :)
Thanks in advance!
Using setAnimationDidStopSelector: is the proper way to solve the generic problem of releasing resources after an animation completes.
Take a step back and reconsider what you're doing here, though. Why are you looking to free the controller you just created? If you are only creating the controller for the purpose of getting at the view, that isn't the right way to do it. Build yourself a factory method to create your view, or use the methods in NSBundle to load the view from a NIB.
You can do this:
[UIView setAnimationDelegate: controller];
[UIView setAnimationDidStopSelector:#selector(release)];
I see you tagged this iphone-sdk-4.0. You could use the new block-based animations to do this and any other cleanup. See the documentation for details.

iAd left white blank screen after closed

I got a problem to integrate iAd in my iPhone apps -- the banner ad is fine when it expends (see http://www.clingmarks.com/iAd1.png and http://www.clingmarks.com/iAd2.png), however, when I close it, it left a white blank screen (see http://www.clingmarks.com/iAd3.png). I couldn't figure out why. Here is how I integrate the ad:
Because I need to support other ads for lower version of iPhone OSes, I add a container view at the top of the apps, whose view controller is AdViewController. When the view is loaded, I create a AdBannerView programmatically and add it as a subview to the AdViewController.view. Here is the code in the viewDidLoad method:
Class adClass = (NSClassFromString(#"ADBannerView"));
if (adClass != nil) {
iAdView = [[ADBannerView alloc] initWithFrame:CGRectZero];
iAdView.frame = CGRectOffset(iAdView.frame, 0, -50);
iAdView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifier320x50];
iAdView.currentContentSizeIdentifier = ADBannerContentSizeIdentifier320x50;
iAdView.delegate = self;
iadViewIsVisible = NO;
[self.view addSubview:iAdView];
} else {
// init google adsense
}
Following are the delegate methods:
enter code here
- (void)bannerViewDidLoadAd:(ADBannerView *)banner {
if (!iadViewIsVisible) {
[UIView beginAnimations:#"animateAdBannerOn" context:NULL];
// banner is invisible now and moved out of the screen on 50 px
banner.frame = CGRectOffset(banner.frame, 0, 50);
[UIView commitAnimations];
iadViewIsVisible = YES;
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
if (iadViewIsVisible) {
[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, -50);
[UIView commitAnimations];
iadViewIsVisible = NO;
}
}
Eventually I figured it out myself. It turns out the ADBannerView's parent view must be a fullscreen view. I my case above, I added AdBannerView to my adView, which is a view with size 320x50. When I changed its parent view to a fullscreen view, everything works. I am not sure if this is a bug in iAd, but certainly something tricky.
When the banner finishes, it moves itself to the top of the screen even if that means having a negative y coordinate. I center the banner when it finishes. In my case there is a view controller for just the banner, so it is only full screen when the ad is clicked.
-(void) bannerViewActionDidFinish:(UIView *)inBanner {
CGRect frame = [inBanner frame];
frame.origin.x = frame.size.width * 0.5;
frame.origin.y = frame.size.height * 0.5;
[inBanner setCenter:frame.origin];
}
Hey David! I know what you mean, I'm also using an own AdvertisementViewController which calls different ad networks.
So iAd is not in a full screen view but inside a 320x50 view.
Simply do this:
-(void) bannerViewActionDidFinish:(ADBannerView *)inBanner {
[self.view setFrame:CGRectMake(0.0f, 0.0f, 320.0f, 50.0f)];
}
So the outer view container (self.view) is resized to its original size. iAd is resizing it to fullscreen for displaying the ad when an iAd is shown.