Ok I want to add a UIImageView as a subview and then remove it after a couple of seconds in the way a splash screen works. I found three different approaches to do it but I can not understand which one is the best approach according to Objective-C and Apple.
Below are the three different approaches:
1)
In my MyAppDelegate.h
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
MyViewController *myViewController;
UIImageView *myImageView;
}
#property (nonatomic, retain) IBOutlet MyViewController *myViewController;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
and in MyAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
myImageView =[[UIImageView alloc] initWithFrame:CGRectMake(0.0,0.0,self.window.frame.size.width,self.window.frame.size.height)];
myImageView.image=[UIImage imageNamed:#"Yoga.png"];
[self.window addSubview:myImageView ];
[self.window bringSubviewToFront:myImageView];
[self performSelector:#selector(removeImage) withObject:nil afterDelay:2.5];
return YES;
}
-(void) removeImage
{
[myImageView removeFromSuperview];
[myImageView release];
[self.window addSubview:myViewController.view];
[self.window makeKeyAndVisible];
}
2) in the second approach:
In my MyAppDelegate.h
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
MyViewController *myViewController;
UIImageView *myImageView;
}
#property (nonatomic, retain) IBOutlet UIImageView *myImageView;
#property (nonatomic, retain) IBOutlet MyViewController *myViewController;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
and in MyAppDelegate.m
#synthesize myImageView;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
myImageView =[[UIImageView alloc] initWithFrame:CGRectMake(0.0,0.0,self.window.frame.size.width,self.window.frame.size.height)];
myImageView.image=[UIImage imageNamed:#"Yoga.png"];
[self.window addSubview:myImageView ];
[self.window bringSubviewToFront:myImageView];
[self performSelector:#selector(removeImage) withObject:nil afterDelay:2.5];
return YES;
}
-(void) removeImage
{
[myImageView removeFromSuperview];
[myImageView release];
[self.window addSubview:myViewController.view];
[self.window makeKeyAndVisible];
}
- (void)dealloc
{
[myViewController release];
[myImageView release];
}
3) in the third approach:
In my MyAppDelegate.h
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
MyViewController *myViewController;
}
#property (nonatomic, retain) IBOutlet MyViewController *myViewController;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
and in MyAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIImageView *myImageView =[[UIImageView alloc] initWithFrame:CGRectMake(0.0,0.0,self.window.frame.size.width,self.window.frame.size.height)];
myImageView.image=[UIImage imageNamed:#"Yoga.png"];
myImageView.tag=22;
[self.window addSubview:myImageView ];
[myImageView release];
[self.window bringSubviewToFront:myImageView];
[self performSelector:#selector(removeImage) withObject:nil afterDelay:2.5];
return YES;
}
-(void) removeImage
{
for (UIView *subview in [self.view subviews]) {
if (subview.tag == 22){
[subview removeFromSuperview];
}
}
[self.window addSubview:myViewController.view];
[self.window makeKeyAndVisible];
}
- (void)dealloc
{
[myViewController release];
}
So to sum up.. The first approach does not use a property for the UIImage only a variable, the second one uses a property and the third one just creates the UIImage and adds it as a subview and then removes it based on its tag..
Which is the right approach to follow..I believe that all three options sound right.. But is there any certain way I should follow. Is any of these options better in terms of memory and performance?
Thanks in advance,
Andreas
You could use an animation attached to the view's layer. Code below fades the view out - but there are many other ways to remove it. (you need to attach the QuartzCore framework)
myImageView.layer.opacity = 0.0;
// this is the state the view will be in after the animation (e.g. invisible)
CABasicAnimation *theFade;
theFade = [CABasicAnimation animationwithKeyPath:#"opacity"];
theFade.duration = 10.0;
theFade.fromValue = [NSNumber numberWithFloat:1.0]; // i.e. visible
theFade.toValue = [NSNumber numberWithFloat:0.0]; // i.e. invisible
[myImageView.layer addAnimation:theFade forKey:#"animateOpacity"];
If you are not going to use the image again, there is no need to keep a pointer to it. Further, if you use IBOutlet, you need to add the view in IB as well. In this specific example I would say option 3 makes the most sence, especially considering that with this choice you can began with a standard "view based application" template and just add the bits about the image view and leave the rest alone. One last observation of choice 3 though; the 2 messages to window;
[self.window addSubview:myViewController.view];
[self.window makeKeyAndVisible];
Appear to be outside the scope of any method. This is likely just a copy and paste error, but make note that they should located within "didFinishLaunchingWithOptions:"
Related
I have a problem with my app (ipad) on iOS4. The Keyboard doesn't work, doesn't display on my webview AFTER the first view (login view).
Appdelagate :
AppDelegate.h
#class RootViewController;
#interface StandardFacileAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *rootViewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet RootViewController *rootViewController;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
rootViewController = [[RootViewController alloc] init];
window.rootViewController = rootViewController;
//[window addSubview:rootViewController.view];
[window makeKeyAndVisible];
return YES;
}
RootViewController :
- (void)viewDidLoad {
[super viewDidLoad];
[self loadViewController];
[self.view addSubview:viewController.view];
}
- (void)loadViewController {
ViewController *viewControllertemp = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
self.viewController = viewControllertemp;
[viewControllertemp release];}
viewController is my login view after request i call the method for change the view (my webview) :
- (void)changeViewToIpadTheWebView:(UIViewController *)fromView{
UIViewController *currentView = (UIViewController*)fromView;
NSLog(#"currentView =>%#",currentView);
if(!ipadTheWebView)
[self loadipadTheWebView];
[currentView.view removeFromSuperview];
for (UIView *view in [self.view subviews]) {
[view removeFromSuperview];
}
[self.view addSubview:ipadTheWebView.view];
NSURL *url = [NSURL URLWithString:#"http://www.google.com/"];
NSURLRequest *requestURL = [NSURLRequest requestWithURL:url];
[ipadTheWebView.webView loadRequest:requestURL];
My webview is ok but if i want search word in google, the keyboard doesn't display (the view scroll) when the textfield have the focus.
What is the problem, this code working on iOS5 but not ios4?
Thanks for your help ;)
Edit :
Thanks Mathieu,
RootViewController.h
#import <UIKit/UIKit.h>
#class ViewController;
#class IpadTheWebView;
#interface RootViewController : UIViewController {
ViewController *viewController;
IpadTheWebView *ipadTheWebView;
}
#property (nonatomic,retain) ViewController *viewController;
- (void)loadViewController;
- (void)changeViewToViewController:(UIViewController *)fromView;
#property (nonatomic,retain) IpadTheWebView *ipadTheWebView;
- (void)loadipadTheWebView;
- (void)changeViewToIpadTheWebView:(UIViewController *)fromView;
- (void)keyboardWillShow:(NSNotification *)notification;
- (void)keyboardWillHide:(NSNotification *)note;
#end
I'm facing an annoying issue and I can't find out why.
I have a UIViewController I present in modal like that :
interviewsViewController *interviewsVC = [[interviewsViewController alloc] initWithNibName:nil bundle:nil];
[interviewsVC setManagedObjectContext:_managedObjectContext];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:interviewsVC];
[interviewsVC release];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
Then when I dismiss the view controller like this :
- (void)dismissViewController
{
[self dismissModalViewControllerAnimated:YES];
}
The dealloc gets called :
- (void)dealloc
{
[_managedObjectContext release];
[_interviewsArray release];
[scrollView release];
[pageControl release];
}
Once the view controller is dismissed, I send an memory warning via the iPhone Simulator Menu and the viewdidunload method gets called :
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.scrollView = nil;
self.pageControl = nil;
}
But there's always an error EXC_BAD_ACCES on the self.scrollView = nil ... More specifically at this line :
#synthesize scrollView;
And I can't find out why ?
If I add a breakpoint on the line above this one, the scrollView is not a zombie or equal to 0x0 ...
Do you have an idea ?
PS : Here's the header :
#import <UIKit/UIKit.h>
#interface interviewsViewController : UIViewController <UIScrollViewDelegate>
{
NSManagedObjectContext *_managedObjectContext;
NSMutableArray *_interviewsArray;
NSUInteger _fetchOffset;
CGFloat _lastXValue;
}
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSMutableArray *interviewsArray;
//IBOutlet
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
#property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
And I set the delegate of the scrollview in the XIB (not in the code).
You need to release properly in dealloc-
Use-
- (void)dealloc {
[_managedObjectContext release];
[_interviewsArray release];
self.scrollView = nil;
self.pageControl = nil;
[super dealloc];
}
ViewDidUnload also be used as that will be helpfull in case of low memory warnings.
I am trying to get my hands on some iphone development. To try to better understand things, I'm going first without IB.
I managed to build a basic app that displays some text. No big deal, until I ran it through Instruments. It shows me some leaks and I cannot understand them.
Any help on this would be greatly appreciated.
MyAppDelegate.h
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MyViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) MyViewController *viewController;
#end
MyAppDelegate.m
#implementation MyAppDelegate
#synthesize window;
#synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// NEXT LINE LEAKS
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
MyViewController.h
#interface MyViewController : UIViewController {
UILabel *firstMessage;
}
MyViewController.m
-(void)loadView {
// Background
CGRect mainFrame = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:mainFrame];
contentView.backgroundColor = [UIColor blackColor];
self.view = contentView;
[contentView release];
// Add UILabel
// NEXT LINE LEAKS
firstMessage = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 30)];
firstMessage.font = [UIFont fontWithName:#"Helvetica" size:16];
firstMessage.textColor = [UIColor whiteColor];
firstMessage.backgroundColor = [UIColor blackColor];
[self.view addSubview:firstMessage];
[firstMessage release];
}
-(void) viewDidLoad {
NSString * msg;
msg=[[NSString alloc] initWithFormat:#"stuff here"];
firstMessage.text=msg;
[msg release];
}
-(void)dealloc {
[firstMessage release];
[super dealloc];
}
Try using #property (nonatomic, retain) UILabel* firstMessage in your header, #synthesize firstMessage in your implementation and then release your firstMessage object in the dealloc method.
Try not to release your firstMessage in loadView. Only release it in your controller's dealloc method.
This is a very important auto rotate issue and easy to reproduce.
My application has a UITabBarController. Each tab is a UINavigationController. Auto rotation is handled with normal calls to shouldAutorotateToInterfaceOrientation and didRotateFromInterfaceOrientation.
The interface rotates normally until I call UIViewController.popViewControllerAnimated and change UITabBarController.selectedIndex.
Steps to reproduce:
Create a demo Tab Bar Application.
Add the following code to the App Delegate .h file:#import <UIKit/UIKit.h>
#interface TestRotationAppDelegate : NSObject {
UIWindow *window;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
// Redefine the interface to cach rotation messages
#interface UITabBarController (TestRotation1AppDelegate)
#end
Add the following code to the App Delegate .m file:#import "TestRotationAppDelegate.h"
#implementation TestRotationAppDelegate
#synthesize window;
#synthesize tabBarController;
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
return YES;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
-(void)dealloc {
[tabBarController release];
[window release];
[super dealloc];
}
#end
#implementation UITabBarController (TestRotation1AppDelegate)
-(void)viewDidLoad {
[super viewDidLoad];
// Add a third tab and push a view
UIViewController *view1 = [[[UIViewController alloc] init] autorelease];
view1.title = #"Third";
UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:view1] autorelease];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObjectsFromArray:self.viewControllers];
[array addObject:nav];
self.viewControllers = array;
// Push view2 inside the third tab
UIViewController *view2 = [[[UIViewController alloc] init] autorelease];
[nav pushViewController:view2 animated:YES];
// Create a button to pop view2
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(50, 50, 220, 38);
[button setTitle:#"Pop this view" forState:UIControlStateNormal];
[button addTarget:self action:#selector(doAction) forControlEvents:UIControlEventTouchUpInside];
[view2.view addSubview:button];
}
-(void) doAction {
// ROTATION PROBLEM BEGINS HERE
// Remove one line of code and the problem doesn't occur.
[self.selectedViewController popViewControllerAnimated:YES];
self.selectedIndex = 0;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#end
The interface auto rotates normally until you tap the button on tab #3.
Your help will be geatly appreciated!
iPhone SDK 3.2 solves this issue.
With previous SDK use [self.selectedViewController popViewControllerAnimated:NO].
I'm new to iPhone programming, and I'm trying to make a simple program without a NIB. I have worked through some NIB tutorials, but I'd like to try some things programmatically.
My code loads without errors, makes the status bar black, and makes the background white. But, I don't think I'm loading my view with a label correctly after that. I presume I'm doing something just fundamentally wrong, so if you could point me in the right direction, I'd appreciate it. I think if I can get the label to show, I'll get some understanding. Here's my code:
//helloUAppDelegate.h
#import <UIKit/UIKit.h>
#import "LocalViewController.h"
#interface helloUAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
LocalViewController *localViewController;
}
#property (nonatomic, retain) UIWindow *window;
#property (nonatomic, retain) LocalViewController *localViewController;
#end
//helloUApDelegate.m
#import "helloUAppDelegate.h"
#implementation helloUAppDelegate
#synthesize window, localViewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
application.statusBarStyle = UIStatusBarStyleBlackOpaque;
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
if (!window) {
[self release];
return;
}
window.backgroundColor = [UIColor whiteColor];
localViewController = [[LocalViewController alloc] init];
[window addSubview:localViewController.view];
// Override point for customization after application launch
[window makeKeyAndVisible];
}
//LocalViewController.h
#import <UIKit/UIKit.h>
#interface LocalViewController : UIViewController {
UILabel *myLabel;
}
#property (nonatomic, retain) UILabel *myLabel;
#end
//LocalViewController.m
#import "LocalViewController.h"
#implementation LocalViewController
#synthesize myLabel;
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
self.myLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 100)];
self.myLabel.text = #"Lorem...";
self.myLabel.textColor = [UIColor redColor];
}
- (void)dealloc {
[super dealloc];
[myLabel release];
}
Add your label to your LocalViewController's view:
- (void)loadView {
[super loadView];
self.myLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 100)];
self.myLabel.text = #"Lorem...";
self.myLabel.textColor = [UIColor redColor];
[self addSubview:self.myLabel];
[self.myLabel release]; // since it's retained after being added to the view
}