Objective C - Access Method befor changing View Controller - ios

I'm trying to call a method before I change the ViewController. Here's my Code:
ViewController.m (First View, here I want to set a String)
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"loginCorrect"]){
[segue.destinationViewController setMail:#"asd"];
}
}
ViewControllerMainMenu.h
- (void)setMail:(NSString*)mail;
#property (strong) NSString *userMail;
ViewControllerMainMenu.m
- (void)setMail:(NSString*)mail
{
self.userMail = mail;
}
As you can see, I want to use the userMail String in the second View, which I get in the first View (a classic Login should be the result).
But I always become this Error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITabBarController setMail:]: unrecognized selector sent to instance 0x147635080'
Hope you can help me, Thanks!
Emanuel

You need to take reference of YourViewController
UITabBarController *tabbar=[segue destinationViewController];
// i am assuming YourViewController at index 0
YourViewController *vc=(YourViewController *)[tabbar.viewControllers objectAtIndex:0];
[vc setMail:#"asd"]

YOu are calling a method on tabbarcontroller which is rely on viewcontroller, so call it properly to reach your goal

It looks like you are sending a message to the object that can not handle this. This is caused because you think you are sending it to the right object but in fact (in runtime) it is not. You should debug and see what is exactly the problem. It might be the retrieving the object you are sending a message or you should have some check if that sending a message should occur in fact - all that depends what you want to achieve. Maybe you will need some casting to help compiler figure out whit what to deal with

I'm guessing your segue destination is a UITabBarController and in it you have a custom UIViewController? We'll need to see proper code in order to answer properly but here's my best guess for now.
First you need to import your class...
#import "ViewControllerMainMenu.h"
Then in prepareForSegue...
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"loginCorrect"]){
UITabBarController *tabBarController = segue.destinationViewController;
ViewControllerMainMenu *controller = tabBarController.viewControllers[0];
controller.mail = #"asd";
}
}
Obviously, this depends on exactly how everything is set up but you should be able to adapt it from here.

Related

Error when setting property in prepareForSegue:

I'm getting the following error when trying to set a string in a public property in prepare for segue. Any idea why?
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController setQuestionObjectId:]: unrecognized selector sent to instance 0x7fa713562b40'
The code is:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"postSegue"]) {
CommentsViewControllerNew *commentsVC = (CommentsViewControllerNew *)[segue destinationViewController];
commentsVC.hidesBottomBarWhenPushed = YES;
PFObject * question=[self.brightenArray objectAtIndex:self.indexPathOfClickedpost.row];
commentsVC.questionObjectId=question.objectId;
NSLog(#"%#",[self.Array objectAtIndex:self.indexPathOfClickedpost.row]);
// commentsVC.question = question;
As you may have already gathered, this is caused because you are sending a setQuestionObjectId: message to a class that doesn't recognise that message. E.g. if you send a reloadData (from UITableView) message to an NSString then you will get a similar exception. This is because NSString doesn't implement (have a method) called reloadData.
This error often happens in the prepareForSegue:sender: method because you are typecasting a UIViewController to a custom subclass (in this case CommentsViewControllerNew). The typecasting happens on this line:
CommentsViewControllerNew *commentsVC = (CommentsViewControllerNew *)[segue destinationViewController];
You are essentially telling the compiler: Yes I know that you think this is a UIViewController but it's actually a CommentsViewControllerNew. The crash comes because, in this case the compiler is right, it is a UIViewController and UIViewController doesn't have a method or property name called questionObjectID
After that long explanation... The fix is to go to your Interface Builder, select the relevant view controller and set its class as CommentsViewControllerNew.
NOTE: If you don't understand, or are unfamiliar with any of what I'm talking about, I suggest you do some reading or do a few tutorials. There are loads of good ones on YouTube.

Passing a PFObject between views is causing values to be null

I'm new to Parse and iOS app development, so please excuse my question if it has an obvious answer.
In my app, the user needs to enter data across multiple views, and for resource efficiency, I am initiating the PFObject as a property in the first view and it is being handed via prepareForSegue to by each scene to its segue's destination view controller.
However, when checking the key-value pairs in the object, I noticed that they are not getting stored in the object. In the debugger, it shows the data in the "estimatedData" section. What is the cause of this? When I try to saveInBackground the object, it fails and says that the object is null.
Here is the code from the FirstViewController.h of the PFObject property declaration.
#property (strong, nonatomic) PFObject *freshChow;
I also call #synthesize freshChow; under the #implementation of the FirstViewController.m.
I later initialize the object in an IBAction when a button is tapped.
- (IBAction)StartCookingProcess:(id)sender {
freshChow = [PFObject objectWithClassName:#"FoodItems"];
[self performSegueWithIdentifier:#"Perform Init Segue" sender:self];
}
And the prepareForSegue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"Start Cooking Process"]) {
Chow_Type_selection *vc = [segue destinationViewController];
vc.freshChow = freshChow;
}
}
This code, with the exception of the StartCookingProcess method is repeated on the subsequent views.
Thanks,
Siddharth

prepareForSegue destination controller property not being set

Here's my prepareForSegue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqual:#"cameraToRollsSegue"]){
ALRollsTableViewController *rollsTableViewController = (ALRollsTableViewController *)[segue destinationViewController];
Camera *c = [self.fetchedResultsController objectAtIndexPath:[self.tableView indexPathForSelectedRow]];
NSLog(#"CAMERA FROM INSIDE PREPARE FOR SEQUE: %#", c);
rollsTableViewController.selectedCamera = c;
}
}
I verify that the camera is not null with NSLog:
CAMERA FROM INSIDE PREPARE FOR SEQUE: <Camera: 0x8dc1400> (entity: Camera; id: 0x8dafba0 <x-coredata://A415F856-5F21-4F08-9CAB-4B2A023B55C3/Camera/p1> ;
ALRollsTableViewController viewDidLoad:
- (void)viewDidLoad
{
NSLog (#"ROLLS TABLE VIEW CONTROLLER : viewDidLoad!");
NSLog(#"(selected camera = %#", self.selectedCamera);
}
results in:
ROLLS TABLE VIEW CONTROLLER : viewDidLoad!
(selected camera = (null)
What might I be doing wrong here that the property is not being set?
UPDATE
With matt's help I've determined that the instance of my destination view controller in my prepareForSeque does not match the actual destination view controller:
rollsTableViewController FROM SEGUE: <ALRollViewController: 0x8d90bf0>
rollsTableViewController FROM viewDidLoad in rollsTableViewController: <ALRollsTableViewController: 0x8c5ab00>
I don't know why this is the case or what to do to fix it.
Post-chat summary:
Well, it was complicated! But basically you were saying this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqual:#"cameraToRollsSegue"]){
ALRollsTableViewController *rollsTableViewController = (ALRollsTableViewController *)[segue destinationViewController];
// ...
}
The problem was that [segue destinationViewController] was not an ALRollsTableViewController. Thus you were not talking to the instance you thought you were talking to, and you were not talking to an instance of the class you thought you were talking to.
The amazing thing is that your code didn't crash when it ran. You were saying this:
rollsTableViewController.selectedCamera = c;
But rollsTableViewController was not in fact an ALRollsTableViewController. You lied to the compiler when you cast incorrectly. Yet you didn't crash when that line ran. Why not? It's because you've got lots of classes with #property selectedCamera! So you were setting the property of a different class. But a property with that same name did exist in that class, so you didn't crash. Thus you didn't discover that this was the wrong class and the wrong instance.

" unrecognized selector sent to instance 0x1f5ea840" when passing values from one ViewController to next in Objective C

I'm getting this error when passing values from one viewcontroller to the next:
"unrecognized selector sent to instance 0x1f5ea840"
"'NSInvalidArgumentException', reason: '-[UIViewController setContainerToLocationFromResultVC:]: "
I've created a strong property in the 2nd VC and it seemed to work well until I made some modifications to use Container View.
Here's my code:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"resToContainerSegue"]) {
containerViewController *containerVC= segue.destinationViewController;
containerVC.container_toLocationFromResultVC=self.toLabel.text; // also tried "toLabel.text" but no use.
containerVC.container_fromLocationFromResultVC=self.fromLabel.text;
}
}
Please let me know if I need to provide any more specific.
I'd be very glad for any help.
Thanks in advance
I got the answer: My destination viewController was not pointing to the proper class. Thanks everyone for helping :)

Set delegate of viewcontrollers in UITabbarController

I have the following setup in my app:
A UITabbarController with 3 viewcontrollers, with embeded UINavigationControllers.
The 3 viewcontrollers inheret/superclass from a UIViewController subclass called "SVC", in order to implement elements which is used in all of the 3. viewcontrollers and prevent duplicated code. In this "SVC" class I have setup a delegate called "dismissDelegate" (which is used to tell when the tabbarcontroller is dimissed).
#protocol ModalViewDelegate <NSObject>
- (void)didDismissModalViewFrom:(UIViewController *)viewController;
#end
#property (weak, nonatomic) id <ModalViewDelegate> dismissDelegate;
My other viewcontroller which segues to the UITabbarController, implements this delegate in order to get information about, when the tabbarcontroller is dismissed.
the SVC class notifies the delegate of dismissal of the tabbar like so:
[self.dismissDelegate didDismissModalViewFrom:self];
I now want to set the delegate of all the viewcontrollers which inherts from the SVC class (all the tabbar viewcontrollers) to this viewcontroller and I try to do this via the prepareToSegue method like so:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ToTab"]) {
UITabBarController *tabBarController = segue.destinationViewController;
for (UINavigationController *navController in tabBarController.viewControllers) {
for (UIViewController *vc in navController.viewControllers) {
_SubclassVC = (SVC *) vc.superclass;
_SubclassVC.dismissDelegate = self;
}
}
}
}
But I get the following error:
+[SVC setDismissDelegate:]: unrecognized selector sent to class 0xbca68
My questions:
Is this the right way to tackle this senario (get information about dismissal of a viewcontroller and setup this delegate in a subclass which is inhereted by multiple viewcontrollers)?
How do I manage to set my first viewcontroller as the delegate of all the viewcontrollers in the tabbar - the SVC class, so I can get notified when the tabbarcontroller is dimissed and solve the error?
+[SVC setDismissDelegate:]: unrecognized selector sent to class 0xbca68
See the +
The plus sign idicates that you are calling a class method. You must have tried setting a class variable by a setter. But a property represents instance variables only. Therefore the setters and getters that are automatically generated are intance methods only. (starting with a minus - in error messages like this).
And that is what you do:
_SubclassVC = (SVC *) vc.superclass;
_SubclassVC.dismissDelegate = self;
For whatever reason (probably by mistake or misunderstanding) you take the vc instance and get its superclass. vc.superclass returns a class object, not an object (meaning not an instance, in Obj-C class objects are objects too).
Then you typecast it to (SVC *) just to stop the compiler from throwing errors (or warnings - not sure).
Well, I guess that you wondered yourself why you have to typecast it at all. That's the reason :)
Next, you assign self to a property dismissDelegate. The compiler does that because you typecasted it to SVC* which does have a property dismissDelegate. The compiler will actually call the setter setDismissDelegate as usual in contructs like this.
BUT at runtime the message (or selector) setDismissDelegate: is not sent to an SVC* but to a class object. And the class SVC does not have a method (or selector) +setDismissDelegate: and therefore cannot resolve the message. And that is exactly what the error message is telling you.
All right, now we get to your questions.
1. Well, it is not the way I would do it, but that is certainly one way of achiving it.
2. If you want to stick with that unusual approach then do this minor change and you will get rid of the error:
for (SVC *vc in navController.viewControllers) {
vc.dismissDelegate = self;
}
There is no point in fetching the superclass object. If you cannot access the property of a superclass then you did something wrong with the inheritance chain.
If you want to be on the save side:
for (UIViewController *vc in navController.viewControllers) {
if (vc isKindOfClass:[SVC class]){ //BTW, this is good usage of the class object
SVC *svc = (SVC*) vc;
svc.dismissDelegate = self;
}
}

Resources