prepareForSegue destination controller property not being set - ios

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.

Related

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

In iOS how to get object fromViewController name?

I know that this is double question. I know that I can use property in toViewController to get name of UIViewController to get NSString which tells me where I am coming from.
Anyway I want to ask if there a simple way to get name of UIViewController when unwinding from segue.
I have a UIViewController with segues to 3 forms. I programatically return to that view controller. I need to run a specific code only when I am returning from one of view controllers. My goal is using string from name of fromViewController start that specific code.
Using UIViewController by NSString from its class name isn't safe enough because the name can be changed.
You can use isKindOfClass instead:
UIViewController *destinationViewController = segue.destinationViewController;
if ([destinationViewController isKindOfClass:[MyViewControllerClass1 class]]) {
// put code related to transition to MyViewControllerClass1
}
else if ([destinationViewController isKindOfClass:[MyViewControllerClass2 class]]) {
// put code related to transition to MyViewControllerClass2
}
You can use:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
UIViewController *destinationViewController = segue.destinationViewController;
NSString * identifier = destinationViewController.identifier;
NSString * title = destinationViewController.title;
}
Create a Custom delegate method in the primary VC, create 3 strings with unique name so that u can identify.
EG.
NSString* stringFrmFORM1, *stringFrmFORM2, *stringFrmFORM3;
-(void)setString:(NSString*)myString{
//set the string from the VC1,2,3 to each string based on Primary VC's strings
}
Call the delegate method from each registration VC, and set those Strings.
You will have your registration strings to each of the Unique strings that you have set, from each of the Registration VC's.
To answer your base question, you can get the name of a class in string form with:
NSString *strClassName = NSStringFromClass([fromViewController class]);
but as #AlexPeda pointed out in ze answer, -isKindOfClass: would be better.
if ([fromViewController isKindOfClass:[SpecificViewController class]]) {
//run your 'specific' code
}

Objective C - Access Method befor changing View Controller

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.

Xcode: Why is my NSLog getting called twice?

I have an ID for a post from my server that I would like to access in two different view controllers. The first view controller is a table view that displays the posts. The user will select a row and the ID for that post will be passed to the next view controller to display details about the post. I use the code below.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
PFObject *objectId = [collectionArray objectAtIndex:indexPath.row];
selectedObjectID = [objectId objectId];
self.objectID = [objectId objectId];
[self performSegueWithIdentifier:#"details" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqual: #"details"]) {
PreviewDetailsViewController *details = (PreviewDetailsViewController *)[segue destinationViewController];
details.objectID = self.objectID;
}
}
"selectedObjectID" is an extern variable and "self.objectID" is a property I set for both classes and tried to set it in the prepareForSegue method. Both of these ways of doing it do the same thing. It passes the variable to the next view controller but when I
NSLog(#"object = %#", self.objectID);
or
NSLog(#"object = %#", selectedObjectID);
in the viewDidLoad of the next view controller, it passes the ID to the next view controller, but it logs out this
object = (null)
object = Zz81bHEeJD
It's like it is getting called twice and the call that matters when I try to query for "self.objectID" or "selectedObjectID" I get
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'Cannot do a comparison query for type: (null)'
which is causing me much headache.
Can anyone explain to me what is going on here and how I can rectify this?
viewDidLoad gets called when your view controller is loaded. When you are in prepareForSegue, you know that the view controller has already been loaded - because you are able to get a reference to it from destinationViewController. This means that viewDidLoad executes before you assign a value to details.objectId.
You should access the property in a method such as viewWillAppear, or trigger your query in a custom setter for the objectId property on your PreviewDetailsViewController.
And I assume that the extern was just for testing, but don't use externs

Custom setter for segue not seeing the object I'm sending to it in iPhone Master/Detail storyboard

Basically, I'm trying to send an object from the master view to the detail view by way of a custom setter. However, as soon as the setter gets called in the detail view, the app immediately crashes. I'm not too good at debugging, but I think it's because the object isn't making it to the setter -- it's seeing it as nil. Could be wrong about that, though.
Here's the code for the segue in the master view:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
CCNewsItem *theNewsItem = self.listOfNewsItems[indexPath.row];
NSLog(#"Preparing to pass: %#", theNewsItem);
[[segue destinationViewController] setSelectedNewsItem:theNewsItem];
}
}
And here it is for the setter in the detail view:
- (void)setSelectedNewsItem:(CCNewsItem *)newItem
{
if (self.selectedNewsItem != newItem) {
self.selectedNewsItem = newItem;
// Update the view.
[self configureView];
}
}
It crashes exactly on the - (void)setSelectedNewsItem:(CCNewsItem *)newItem line. I've made super-sure that the object being passed is valid (I log it to double check, and all seems well), but it seems that it either isn't making it to the setter or it's somehow exploding when it hits it.
Any ideas? Thanks!
As requested, here's the logs/exception
This is what my NSLog shows on the object I'm trying to pass:
2013-11-02 14:18:23.660 Curtis Consulting[14862:60b] Preparing to pass: <CCNewsItem: 0x14e70580>
When the app stops on the setter's first line (I'm not sure why; I have all breakpoints disabled), it shows the values of newItem (the passed object) as:
newItem CCNewsItem * nil 0x00000000
NSObject NSObject
_headline NSString * nil
_body NSString * nil
_url NSURL * nil
Edit 2
Since, as near as I can tell, there is no way to copy the error it's showing (in a green bar at the right, but I don't have any breakpoints turned on), here's my transcription of it:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x27c84ff8)
In your setter method change:
if (self.selectedNewsItem != newItem) {
self.selectedNewsItem = newItem;
to
if (_selectedNewsItem != newItem) {
_selectedNewsItem = newItem;
Because your current code has an infinite loop calling the accessor method. Be sure you know what using self. means...

Resources