This class is a subclass of UITabBarViewController.
In my init parent view controller file I have this:
UIBarButtonItem *button1 = [[UIBarButtonItem alloc]
initWithTitle:#"Button1"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(button1:)];
self.navigationItem.rightBarButtonItem = button1;
[button1 release];
And the method:
-(IBAction)button1:(id)sender {
if (self.nvc == nil) {
ChildViewController *vc = [[ChildViewController alloc] init];
self.nvc = vc;
[vc release];
}
[self presentModalViewController:self.nvc animated:YES];
I want to get an value from the parentviewcontroller in my childviewcontroller class, which also is a UITabBarViewController subclass.
How do I do this, I have tried several hours, and I only get a nil-reference.
The object I want to get(which is a property in the parent) is a NSString.
Thanks in advance
The cleanest way would probably be to create a ChildViewControllerDelegate protocol that the parent view controller implements. This is a common idiom in iOS development.
#protocol ChildViewControllerDelegate
- (NSString *)getSomeNSString;
#end
Then you should make ChildViewController have this delegate as an instance variable and be assignable via a property
#property (nonatomic, assign) id<ChildViewControllerDelegate> delegate;
Now from within ChildViewController you can use this delegate to access methods on the delegate which in your case will be ParentViewController. This will allow you to retreive the string you want.
[delegate getSomeNSString]
This may seem like a lot of work for something simple but it avoids the problems inherit with storing a back reference from ChildViewController to its parent ParentViewController.
There are a lot of ways to do this. The easiest would be to add a property to ChildViewController that points to your parent view controller. You could call it delegate. Then the method will look like:
-(IBAction)newbuilding:(id)sender {
if (self.nvc == nil) {
ChildViewController *vc = [[ChildViewController alloc] init];
vc.delegate = self;
self.nvc = vc;
[vc release];
}
[self presentModalViewController:self.nvc animated:YES];
}
Then from the ChildViewController instance you can access self.delegate.someProperty.
There are also ways to get the parent view controller without your own explicit reference (typically self.tabBarController, self.navigationController depending on context), but the above method is fool-proof, understandable and easy to debug.
Related
I have some problem with my singleton and UIViewController there;
Singleton.h
#property (nonatomic, retain) UIViewController *viewController;
Singleton.m
...
#synthesize viewController = _viewController;
- (void)load {
self.viewController = [[[UIViewController alloc] initWithNibName:#"NibName" bundle: nil] autorelease];
}
- (void)unload {
[_viewController release];
}
This viewController using by different part of the application via pushViewController:animated:. But sometimes I need to release viewController by calling method - (void)unload of Singleton class! If pushViewController:animated: never call for viewController everything is well and dealloc is calling, but if pushViewController(and viewController perform viewDidLoad), dealloc isn't work. If I do something like self.viewController = nil; dealloc calling twice... What I'm doing wrong???
Your unload function should only consist of:
- (void)unload {
self.viewController = nil;
}
When you set a retained property to nil, it releases the instance variable AND nils it. You are simply leaving a dangling pointer on your property here.
You need to set it to nil after releasing it:
[_viewController release];
_viewController = nil;
Otherwise the next person who comes along will try to do stuff with an invalid pointer.
Is there a way to check if a UIViewController is loaded in memory/visible on screen?
Something like this:
if([ContentRvController exists]){
contentView *ContentRvController = [[contentView alloc]
initWithNibName:#"contentView" bundle:nil]; //ContentView is a custom UIViewController
....
//Code to set the UIViewController
....
}
else{
[ContentRvController release];
}
That should happen when a button (that right now initializes the ViewControllers) is tapped. Right now, when tapped it opens n ViewControllers, it is supposed to display only one at a time.
Thats pretty much it, greetings and hope you can help me out.
Is this based on existing code?
Classes should start upper case, and instances should be camel case, e.g.
if([contentRvController exists]){
ContentView *contentRvController = [[ContentView alloc]
initWithNibName:#"contentView" bundle:nil]; //ContentView is a custom UIViewController
....
//Code to set the UIViewController
....
}
else{
[contentRvController release];
}
it is probably worth declaring it in the header, i.e.
#interface SomeClass : NSObject {
}
#property(non-atomic, retain) ContentView *contentRvController;
#end
and then in code you could do
if(contentRvController!=nil){
ContentView *aView=[[[ContentView alloc] init] autorelease];
self.contentRvController=aView;
}
Also, don't do the else{[contentRv release];} bit, if you have autoreleased it anywhere, this will leak at some point.
If you are using UINavigationController check for the property topViewController.
I have one view who calculates location and reverser geocode to get the zip code. Then it calls another view where I want to display weather results based on that zip code.
In the first view controller I do this once user clicks on the button to turn the page:
- (IBAction) showMyWeather : (id)sender {
WeatherApp *weather = [[WeatherApp alloc] initWithNibName:nil bundle:nil];
weather.zipcode = placemarkZip; //this one seems not to be doing the job
weather.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:weather animated:YES];
}
And at the WeatherApp I would like to read now zipcode, which is declared in this view controller .h:
#interface WeatherApp : UIViewController{
IBOutlet UIButton *done;
MKPlacemark *zipcode;
}
#property (nonatomic, retain) MKPlacemark *zipcode;
How can I use this code to transfer this zipcode to the WeatherApp? Thanks!
Yes, this is a fine way to pass information into your new object.
Alternatively, you could create a custom initializer for WeatherApp like
- (id)initWithZipCode:(NSString *)zip;
and then in the implementation file, it could be like this:
- (id)initWithZipCode:(NSString *)zip
{
self = [super init];
[self setZipcode:zip];
return self;
}
Finally, you could instantiate the class like so:
- (IBAction)showMyWeather:(id)sender
{
WeatherApp *weather = [[WeatherApp alloc] initWithZipCode:placemarkZip];
[weather setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:weather animated:YES];
[weather release]; // No longer needed with ARC... just sayin'
}
Finally, if you're going to continue to pass in information as you do above, I'd question why you're using initWithNibName:bundle:. If you're just going to pass nil to both, why not just use [[WeatherApp alloc] init]?
I want to know how to pass values between views in popViewControllerAnimated .
Here is my scenario:
I have a view which contains tableview on selecting the cell we go to another view where i need to enter value in textbox and i click a button to go back to the previous view where i need to display the textbox value in the table view cell.
How can i do this ?
This what i have done:
NewContact *nc = [[NewContact alloc] initWithNibName:#"NewContact" bundle:nil];
// ...
// Pass the selected object to the new view controller.
nc.name=[firstName text];
//[self.navigationController pushViewController:nc animated:YES];
[self.navigationController popViewControllerAnimated:YES];
[nc release];
In ViewControllerB, declare delegate and set action for popViewControllerAnimated:
#interface ViewControllerB : UIViewController {
id delegate;
}
#property (nonatomic, retain) id delegate;
#synthesize delegate;
- (id) init ... {
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(didBack:)] autorelease];
}
- (void) didBack:(id)sender {
if ([delegate respondsToSelector:#selector(setProperty:)]) {
[delegate setProperty:property];
}
[self.navigationController popViewControllerAnimated:YES];
}
In ViewControllerA, provide a function to set the local property and set delegate:
ViewControllerB controllerB = [[ViewControllerB alloc] init...];
[controllerB setDelegate:self];
[self.navigationController pushViewController:controllerB animated:YES];
[controllerB release];
You need to store value in one of the global variable for example you can declare in appDelegate file. See this post for that
If you are using UITextField then you can store value in above variable from UITextField in below delegate method.
- (BOOL)textFieldShouldReturn:(UITextField *)textField;
Hope this help.
You could use NSNotificationCenter for this, passing an object along with the call.
Howto: Send and receive messages through NSNotificationCenter in Objective-C?
Based on your requirement in your comment,
Say you navigate from ViewControllerA instance to ViewControllerB instance and you wish to call ViewControllerA's methods, you can do it like this,
ViewControllerA * viewControllerA = (ViewControllerA *)self.parentViewController.
[viewController methodToCall];
To use this to address the requirement in the question, you can use a property.
viewControllerA.name = firstName.text; // Bits from your code snippet
However in a table view I would expect you to have a mutable array powering the data source. You can refer to it, assuming that it is an property.
[viewControllerA.dataSourceArray addObject:firstName.text];
I'm going mad using navigation controllers on the iPhone.
I have an app, with a main xib (the one with the window) inside wich I have put a NavigationController, inside wich I have a viewController. Everything is connected and the ViewController is defined with the correct inherited class name.
In the didFinishLaunchingWithOptions, i have :
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
In the .h I have :
#interface MainAppDelegate : NSObject <UIApplicationDelegate> {
IBOutlet UIWindow *window;
IBOutlet UINavigationController* navigationController;
}
#property (nonatomic, retain) UIWindow *window;
#property (nonatomic, retain) UINavigationController* navigationController;
#end
Then in the First ViewController I have a button connected to this method :
- (IBAction) definePreferences:(id)sender {
PreferencesController *nextWindow = [[[PreferencesController alloc] initWithNibName:#"Preferences" bundle:nil] autorelease];
UINavigationController* navController = [[[UINavigationController alloc] initWithRootViewController:nextWindow] autorelease];
[self.navigationController presentModalViewController:navController animated:YES];
}
all items in the main xib seems to be connected... and retained by the properties. The AppDelegate with its window and navigationController... the Window rootviewcontroller with the same navigationController... and the file owner with the app delegate...
Everything runs fine, but the preferences window never appears...
Can you see why ?
If needed, I must say that this first view controller makes the camera interface appear and put an overlay over it. The button is onto this overlay. The imagePicker is show like this in viewDidAppear :
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
[self presentModalViewController:picker animated:YES];
[picker release];
EDIT :
In viewDidAppear, self.navigationController is ok at the start and end of method.
In definePreferences, self.navigationController is nil. Nothing is called beetween those two calls.
Nothing
EDIT :
The problem may come from the way I init the viewController on which the button is.
Here is the method called from the firstView called by the Navigation Controller.
- (void) viewDidAppear:(BOOL)animated {
UIImagePickerController* picker = [[UIImagePickerController alloc] init];
// Set the image picker source:
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.showsCameraControls = NO;
picker.navigationBarHidden = YES;
picker.wantsFullScreenLayout = YES;
// Insert the overlay
OverlayViewController* overlayController = [[OverlayViewController alloc] initWithNibName:#"Overlay" bundle:nil];
picker.cameraOverlayView = overlayController.view;
// Show the picker:
[self presentModalViewController:picker animated:NO];
[picker release];
[super viewDidAppear:YES];
}
But... how should I do ?
First, never call an IBAction setPreferences:. That violates KVC, and can eventually cause all kinds of bizarre behaviors. setX: is a reserved name for the setter of the property named x.
You should not be creating a nav controller in this method (i.e. navController). You should be using the one you created in the NIB (self.navigationController). Check if that is nil. If it is, then you either didn't set up a navigation controller in the NIB, or you didn't wire it to this view controller.
You should also verify that nextWindow is non-nil.
I've finaly solved the problem.
See https://stackoverflow.com/questions/5317968/iphone-camera-overlay-going-down-after-a-modal-view-transition
I have some hair less... :-)