Memory management is a very important issue in iPhone. So I am asking a very general question.
There are two ways to call a the viewController of another class.
Way 1:
AnotherClassViewController *viewController = [[[AnotherClassViewController alloc] initWithNibName:#"AnotherClassView" bundle:nil] autorelease];
[self.navigationController pushViewController:viewController animated:YES];
Way 2:
#import "AnotherClassViewController.h"
#interface ThisClassViewController : UIViewController{
AnotherClassViewController *myViewController;
}
#property (nonatomic, retain) AnotherClassViewController *myViewController;
#end
#implementation ThisClassViewController
#synthesize myViewController;
- (void) pushAnotherViewController{
if(self.myViewController == nil){
AnotherClassViewController *tempViewController = [[AnotherClassViewController alloc] initWithNibName:#"AnotherClassView" bundle:nil];
self.myViewController = tempViewController;
[tempViewController release];
}
[self.navigationController pushViewController:myViewController animated:YES];
}
- (void)dealloc{
self.myViewController = nil;
}
#end
So the obvious question is, which is the best way to call the viewController of other class ?
Way1 or Way2?
Suggestions and comments are openly invited.
Please comment and vote.
Hmm... To keep things simple, why not just:
MyViewController* viewController = [[MyViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
Way 1 is simpler.
Way 2 lets the first controller keep a reference to the pushed view controller. If you need that reference, then this would be useful.
There is no clear answer here. It depends upon your needs. The general rule, of course, is to make the code as simple as possible, but no simpler.
Related
I've set up a navController, which appears after tapping a button. However, if I tap the button I get the error of: "Warning: Attempt to present <UINavigationController>: 0xab5d9d0 on <MyApp: 0xadaa320> whose view is not in the window hierarchy!"
Does anyone know how to solve this? I also tried something on Stackoverflow but it wasn't my solution.
Here my code for opening the navigationcontroller:
I dont know if somebody know this photogallery but if you don't, here is the project.
My code (MyApp.m):
#import MyApp.h
...
//some stuff
- (void)launchGalleryView
{
MWPhotoBrowser *browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
// Set browser options.
browser.wantsFullScreenLayout = YES;
browser.displayActionButton = NO;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:browser];
NSMutableArray *photos = [[NSMutableArray alloc] init];
MWPhoto *photo;
photo = [MWPhoto photoWithFilePath:[[NSBundle mainBundle] pathForResource:#"callculator" ofType:#"jpg"]];
photo.caption = #"The calculator is soo beateful...";
[photos addObject:photo];
self.photos = photos;
[self presentModalViewController:navController animated:NO];
}
Thanks in advance.
Edit:
it is in the recources and in the compile sources but in the resources you can see that it is red (the storyboard). Maybe it's caused by this?
The Second controller .h:
#class MyApp;
#interface Second : UIViewController <MWPhotoBrowserDelegate> {
}
#property (nonatomic, retain) MyApp* vC;
#end
The Secnond controller .m:
#import "Second.h"
#import "MyApp.h"
#interface Second ()
#end
#implementation Second
#synthesize vC;
//some stuff in here
//the action
- (IBAction)dothis:(id)sender {
NSLog(#"launch the navcontroller");
[self.vC launchGalleryView];
}
MyApp.h:
#import "Second.h"
#interface myApp : UIViewController <MWPhotoBrowserDelegate> {
}
-(void)launchGalleryView;
NSArray *_photos;
NEW EDIT:
I found that I have to call the method "launchGalleryView" in the viewDidAppear but how can I do this without calling the navcontroller everytime the view loads? Does anyone know how to do this?
i checked your project.. wasn't able to sort out the proper issue..
but i tried a hack and it worked..
replace this line with
[self presentModalViewController:navController animated:YES];
this
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentModalViewController:navController animated:YES];
The following code isn't working out for me. Whenever the method is called the app crashes What have i done wrong?
This code does use a storyboard format
in the .h file
#class SendVideoViewController;
...
#property (nonatomic) SendVideoViewController *sendVideoViewController;
in the .m file
#import "SendVideoViewController.h"
...
#synthesize sendVideoViewController;
...
- (IBAction)signMeUpButtonPressed:(id)sender {
termsAndConditionsViewController = [[TermsAndConditionsViewController alloc] init];
[self presentViewController:termsAndConditionsViewController animated:YES completion:nil];
//[self.view insertSubview:termsAndConditionsViewController.view atIndex:0];
}
Your code should read:
sendVideoViewController = [[SendVideoViewController alloc] init];
[self presentViewController:sendVideoViewController animated:YES completion:nil];
Right now you are instantiating a generic UIViewController class. In order to create an object of the type which you have defined in your SendVideoViewController class, you need to call +alloc on that class, not UIViewController. You might want to brush up on the documentation.
Try this:
sendVideoViewController = [[SendVideoViewController alloc] init];
[self presentViewController:sendVideoViewController animated:YES completion:nil];
I am new to the objective C programming and I am in a position where I need to create an iPhone App really quickly.
I am using XCode 4.2
I have a problem transferring an NSString variable from one view to the other .
the two views are in two different sets of .h and .m classes
in the first class in the .h i have something like this
#interface firstview : UIViewController {
NSString *test;
}
-(IBAction)testbutton
#end
in the .m of the firstview I have
-(IBAction)testbutton{
secondView *second;
[second setText:text]; //set text is a function that will take an NSString parameter
second= [[secondView alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
}
in the .h of the secondView I wrote
#interface secondView : UIViewController{
-IB
}
You've got the right idea, but you're trying to call -setText: before second points to a valid object! Do this instead:
-(IBAction)testbutton{
secondView *second;
second = [[secondView alloc] initWithNibName:nil bundle:nil];
[second setText:text]; //set text is a function that will take an NSString parameter
[self presentModalViewController:second animated:YES];
}
Also, the interface you give for your secondView class looks both incorrect and incomplete -- I'm not sure what you're trying to do with the -IB part. And it'd help in the future if you follow the usual Objective-C naming convention and start class names with an uppercase character: SecondView instead of secondView. Finally, I'd advise against naming a view controller ending in "...View", since that makes it easy to confuse the view controller with a UIView. All together, it should look something like this:
#interface SecondViewController : UIViewController{
NSString *text;
}
#property (retain, nonatomic) NSString *text;
#end
Declaring text as an instance variable is optional there -- if you don't do it, the compiler will create an ivar if you synthesize the accessors for your text property.
Change your code to this:
-(IBAction)testbutton{
secondView *second;
second = [[secondView alloc] initWithNibName:nil bundle:nil];
[second setText:text]; //set text is a function that will take an NSString parameter
[self presentModalViewController:second animated:YES];
}
In your original version, you were initializing (i.e. instantiating) your second view after calling setText: on it. You need to initialize it and then set the text.
You need to set the text after you allocate and initialize.
-(IBAction) testButton {
secondView *second = [[[secondView alloc] initWithNibName:nil bundle:nil] autorelease];
[second setText:text];
[self presentModalViewController:second animated:YES];
}
EDIT: Added Source Project
--> I uploaded a sample project that clearly shows my dilemma which can be found here <--
I created a Split View-based Application. I then added a second UINavigationController to the DetailViewController inside the MainWindow.xib.
I then pop a new UIViewController Subclasses when a toolbar item is clicked. I use the following code to conduct the pop:
DocumentDetailVC *DetailViewController = [[DocumentDetailVC alloc] initWithNibName:#"DocumentDetailVC" bundle:[NSBundle mainBundle]];
[detailViewController.detailNavController pushViewController:DetailViewController animated:YES];
DocumentsVC *RRequestViewController = [[DocumentsVC alloc] initWithNibName:#"DocumentsVC" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:RRequestViewController animated:YES];
This works. The issue I am having is how do I pass information or function calls from the Main side of the Split View to the Detail side of the Split view?
If I present the UIViewController via the following method:
DocumentDetailVC *RRequestViewController = [[DocumentDetailVC alloc] initWithNibName:#"DocumentDetailVC" bundle:[NSBundle mainBundle]];
RRequestViewController.delegate=self;
RRequestViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[RRequestViewController setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:RRequestViewController animated:YES];
[RRequestViewController release];
RRequestViewController = nil;
I am able to complete a reach back through a protocol as intended.
DocumentDetailVC, when loaded via the pushViewController, the hierarchy is as follows:
NSLog([NSString stringWithFormat:#"%#",self]);
//self = <DocumentDetailVC: 0x4e0d960>
NSLog([NSString stringWithFormat:#"%#",self.parentViewController]);
//self.parentViewController = <UINavigationController: 0x4e0ce30>
NSLog([NSString stringWithFormat:#"%#",self.parentViewController.parentViewController]);
//self.parentViewController.parentViewController = <UISplitViewController: 0x4e0d0f0>
Thank you for your assistance. This problem is consuming my life!
--> I uploaded a sample project that clearly shows my dilemma which can be found here <--
Ok, I know am very late for answer but this answer is, I think, perfect and working. Try it. Open your RootViewController.h, on the top write this line:
#import "Left.h"
#import "Right.h"
in #interface RootViewController write this lines
Left *lefty;
Right *righty;
after that declare property as,
#property (nonatomic, retain) Left *lefty;
#property (nonatomic, retain) Right *righty;
go to ROOTVIEWCONTROLLER.M file synthesize as,
#synthesize lefty;
#synthesize righty;
after that in RootViewController.m just replace your function with this one
- (IBAction)myBtnPushed{
NSLog(#"myBtnPushed");
lefty = [[Left alloc] initWithNibName:#"Left" bundle:[NSBundle mainBundle]];
righty = [[Right alloc] initWithNibName:#"Right" bundle:[NSBundle mainBundle]];
lefty.delegate=righty;
[self.navigationController pushViewController:lefty animated:YES];
[detailViewController.navigationController pushViewController:righty animated:YES];
}
in delloac write this,
[lefty release];
lefty = nil;
[righty release];
righty = nil;
It's done, run your app. I tested, it's done.
I'm using two UIViewController in Application Delegate and navigating to UIViewController using presentmodalviewcontroller. But Problem is that presentmodalviewcontroller works for first time UIViewController and when i want to navigate to second UIViewController using presentmodalviewcontroller then its showing first UIViewController.
The following is the code:-
-(void)removeTabBar:(NSString *)str
{
HelpViewController *hvc =[[HelpViewController alloc] initWithNibName:#"HelpViewController" bundle:[NSBundle mainBundle]];
VideoPlaylistViewController *vpvc =[[VideoPlaylistViewController alloc] initWithNibName:#"VideoPlaylistViewController" bundle:[NSBundle mainBundle]];
if ([str isEqualToString:#"Help"])
{
[tabBarController.view removeFromSuperview];
[vpvc dismissModalViewControllerAnimated:YES];
[viewController presentModalViewController:hvc animated:YES];
[hvc release];
}
if ([str isEqualToString:#"VideoPlaylist"])
{
[hvc dismissModalViewControllerAnimated:YES];
[viewController presentModalViewController:vpvc animated:YES];
[vpvc release];
}
}
Can Somebody help me in solving the problem?
You're making a new hvc and vpvc each time you run this function.
The first time through, I assume you call removeTabBar:#"Help", it makes a hvc and vpvc and then shows the correct one.
The second time you call it removeTabBar:#"VideoPlayList", you are making a new hvc and vpvc. This means that when you call hvc dismissModalViewController:YES]; you're not removing the one you added before, you're removing the new one that you just made which isn't being displayed at all!
To solve this you need to make your two controllers as properties in your app delegate and create them in the applicationDidFinishLaunching method.
Add these into your app delegate's .h file:
#class MyAppDelegate {
HelpViewController *hvc;
VideoPlaylistViewController *vpvc;
}
#property (nonatomic, retain) HelpViewController *hvc;
#property (nonatomic, retain) VideoPlaylistViewController *vpvc;
#end
and in your app delegate's .m file :
- (void)applicationDidFinishLaunching:(UIApplication *)application {
...
self.hvc = [[[HelpViewController alloc] initWithNibName:#"HelpViewController" bundle:nil] autorelease];
self.vpvc = [[[VideoPlaylistViewController alloc] initWithNibName:#"VideoPlaylistViewController" bundle:nil] autorelease];
...
}
and remove the first two lines in removeTabBar