When I try to push a view controller to my UINavigationController I get a NSInvalidArgumentException thrown with the error message "unrecognized selector sent to instance". But this only happens when I name my UINavigationController ivar anything other than "navigationController". Is there a reason for this?
Not sure how your code is structured, but every UIViewController has a navigationController property. (See http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html)
So, [self navigationController] is returning the property from the current view controller (whatever self is), not what you've named in your AppDelegate.
Related
I've already spent the whole day in an issue and did not find a solution yet. I have a UITabBarViewController and I am trying to fire off a modal segue from one of its tabs. I've already created the view I want to segue to, created the segue itself (from the tab's view controller to the target's view controller) and the identifier. In order to test my segue I created a UIButton in my tab and wrote the following code on its action:
[self performSegueWithIdentifier:#"showProductInfo" sender:self];
The modal segue worked fine. But if I try to write the same code to be performed somewhere else (inside a specific method that is called after I receive a web service response) the segue simply does not work. I get the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver () has no segue with identifier 'showProductInfo''
This is driving me crazy! Any help is more then welcome.
Editting:
Some additional findings:
If I take off the performSegue from the method I am currently using (which by the way is called by DidFinishLoading) and put it on ViewDidLoad the segue is performed successfully.
Thinking that it could be a thread related issue I included the performSegue inside a dispatch_async(dispatch_get_main_queue()... But the error is the same !
If your destination viewcontroller is inside a navigationcontroller, then take a look at this question:
http://stackoverflow.com/questions/8041237/how-to-set-the-delegate-with-a-storyboard
Furthermore, from the error it looks like the segue you are trying to perform is not attached
to the viewcontroller you are starting from. So,Try to remove the seque and drag it from the
viewcontroller.
The current view controller must have been loaded from a storyboard. If its storyboard property is nil, perhaps because you allocated and initialized the view controller yourself, this method throws an exception.
Make sure you have Storyboard ID for your destination VC (in this example myViewController).
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"myStoryboard" bundle:[NSBundle mainBundle]];
UIViewController *myViewController = [storyboard instantiateViewControllerWithIdentifier:#"MyController"];
[self.navigationController pushViewController:myViewController animated:YES];
I have a cancel button, when i press cancel button then i pop my current viewcontroller. Before popping my controller, i want to access one member (which is a class Student) of previous view controller. So i am doing this way:
StudentProfileViewController *controller = (StudentProfileViewController*)self.parentViewController;
NSLog(#"%#", controller.student);
My app crashes on line NSLog, error is this:
[UINavigationController student]: unrecognized selector sent to instance 0x6865180
Strange part is its says "[UINavigationController student]" but my controller is UIViewController.
Can anyone shed a light on this. I know some silly mistake is being done.
Thanks
The parentViewController would return the controller you are looking for only if you had presented modally from that view in the first place. It looks to be that you are trying to reference the previous controller in the stack, not the presenting view.
In your case, the parentViewController is the navigationController if that is how you presented. You are casting it to the controller class you wish it to be but that doesn't make it so.
More appropriate method would be to have passed the object you wish to reference in the init method or, most preferably, make a delegate method to tell the former view when this controller is complete, then let the former view react as intended.
I am displaying a modal view controller from an NSObject.
I call presentModalViewController:animated on self.sender which is another view controller. The view controller displays fine, but when I push a button in the view, I get the following error:
-[__NSCFType buttonCancelPressed:]: unrecognized selector sent to
instance
This is how I display the modal view controller from my NSObject:
FBComposeViewController *composeViewController = [[FBComposeViewController alloc] initWithNibName:#"FBComposeViewController" bundle:nil];
[self.sender presentModalViewController:composeViewController animated:YES];
The button is hooked up to a selector in FBComposeViewController using Interface Builder.
Does anyone have an idea why I might be getting this error?
The problem is probably the binding in FBComposeViewController.xib. What is the target-action for the cancel button set to?
Why are you using self.sender? Assuming sender is a UIButton object.
Assuming, this line of code is written in a Controller Class, use:
[self presentModalViewController:composeViewController animated:YES];
I have a crash on [self.navigationController setToolbarHidden:NO animated:YES] located in my viewWillAppear when I come back to the UIViewController using that toolbar. With this Error *** -[CALayer retain]: Message sent to deallocated instace 0x5d0e0a0 I am not expressly releasing the toolbar but the class where I am setting it is autoreleased.
Also am I incorrect in assuming that the toolbar is on the navigationController?
You should retain a reference to the toolbar in the navigation controller in which it appears. You should not set UI interfaces in transient classes. It is important to separate your models from the views via a controller - thus "Model-View-Controller" design pattern.
A tool bar does not necessitate a navigation controller. Do not confound with a navigation bar, which can be sort of similar.
There was a cheap and easy way to get this to work.
[self.navigationController.toolbar init];
I am able to pass a variable forward from view controller to view controller by pushing its view controller onto the navigation stack. An example of how I do it would be this:
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
controller.myString = stringToPass;
[self.navigationController pushViewController:controller animated:YES];
[controller release];
However, what do I do if I want to pass a variable BACK UP the navigation stack? Using popViewControllerAnimated rather than pushViewController does not pass the variable up like I thought it would.
I need to be able to access the variable several pops up from the view controller it is defined in.
Any help will be greatly appreciated :)
You're passing values, not variables.
A view controller should not be responsible for popping itself. With Apple's view controllers (e.g. UIImagePicker), it is the parent view controller's responsibility to do the popping; the parent VC can also obtain the current value. (Not entirely correct; it might access the value before a keyboard autocompletion is applied)
Alternatively, if it's a value that can be shared globally, you can store it in your application delegate.
You can get a hold of the navigation controller in the VC stack using self.navigationController. You can just call some method like
[self.navigationController setMyString:stringToPassUp];
There are several more ways, e.g. self.tabBarController for the tabbarcontroller up in the stack, or most simply
[self.parentViewController setMyString:stringToPassUp];
edit given the downvotes on the examples above, and nobody giving a better explanation, let's discuss the proper way to do this.
If you have some object (like your MyViewController *controller) and that object has something to tell you, the usual approach is this:
MyViewController gets a delegate property, of type (id)
the view controller instantiating the MyViewController, sets this delegate property, like so:
controller.delegate = self;
MyViewController will, when it has something to say, do something like:
[self.delegate delegateMessage:arg1]; to "pass the message up" as you put it.
To do it perfectly, you may want to create your own #protocol MyViewControllerDelegate, and declare the class which would be setting controller.delegate = self; to adopt this protocol, by putting <MyViewControllerDelegate> on the #interface line. The delegate property of MyViewController should then be declared id<MyViewControllerDelegate> delegate;, so that the [self.delegate ...] messages can be matched to the protocol specification.
Basically the whole Cocoa Touch API works like this. Just have a look around for ideas how to implement your interaction.