prepareForSegue working on simulator but not on device - ios

I am so tired of trying to make this work so i hope somebody here will be able to solve this for me..
I am using this code to segue to a UINavigationController. This code WORKS on simulator but NOT on a real device:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
static NSString *segueIdentifier = #"ShowDetails";
if ([[segue identifier] isEqualToString:segueIdentifier]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *navigationController = segue.destinationViewController;
DetailViewController *detailViewController = [navigationController viewControllers][0];
detailViewController.selectedGameIdNumber = [NSString stringWithFormat: #"%ld", (long)indexPath.row];
detailViewController.selectedSection = [self.sectionNames objectAtIndex:indexPath.section];
}
}
On the real device it crashes at:
DetailViewController *detailViewController = [navigationController viewControllers][0];
with the error:
-[DetailViewController viewControllers]: unrecognized selector sent to instance
Then i have this code that i tried. This code WORKS on device but NOT on simulator:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
static NSString *segueIdentifier = #"ShowDetails";
if ([[segue identifier] isEqualToString:segueIdentifier]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
DetailViewController * detailViewController = (DetailViewController *)segue.destinationViewController;
detailViewController.selectedGameIdNumber = [NSString stringWithFormat: #"%ld", (long)indexPath.row];
detailViewController.selectedSection = [self.sectionNames objectAtIndex:indexPath.section];
}
}
On the simulator it crashes at:
detailViewController.selectedGameIdNumber = [NSString stringWithFormat: #"%ld", (long)indexPath.row];
With the error:
-[UINavigationController setSelectedGameIdNumber:]: unrecognized selector sent to instance 0x7fa1d273e8
Am i doing something wrong or should i just run with the second code that works on real device?
I want to have a clean solution so please do enlighten me if i am doing something wrong. Thank you all.

The issue is with how you are accessing the view controller. On the device the view controller hierarchy is different from on the simulator, and so the two solutions both only work in their own scenario. Of course it isn't the simulator that is different, but rather the device you are simulating (guess is iPad)
Be aware that, especially with splitViewcontrollers, but also with other framework provided view controllers that the functionality of the controllers may vary based on the target device. This change often bites you when you make assumptions about indexes of view controllers and the like.
Debug on the simulator, switching between device types and po the view controller and I think you will see what I mean.

Here's my solution: creating a generic struct and cast the customized viewcontroller by function call. The advantage is that you can reuse this function everywhere you need it.
(Though my code is in written in swift rather than Objective-C, I think the way of solution is just alike)
struct DestinationController<T: UIViewController> {
func get(segue: UIStoryboardSegue) -> T {
if let navigation = segue.destinationViewController as? UINavigationController{
return navigation.viewControllers.first as! T
}
return segue.destinationViewController as! T
}
}

Related

SWRevealViewController does not recognize sectors for destinationViewController

I am using John Lluch's SWRevealViewController which works great, except I cannot figure out how to set selectors in the destination view controller as I do in segues for other UIViewControllers.
Has anyone else encountered this problem?
Here is my code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Set the title of navigation bar by using the menu items
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
if ([segue.identifier isEqualToString:#"goalSegue"]) {
if ([segue.destinationViewController respondsToSelector:#selector(setTitleForViewController:)]) {
// use performSelector:withObject: to send without compiler checking
// (which is acceptable here because we used introspection to be sure this is okay)
NSString * titleText = #"Athlete Goals";
[segue.destinationViewController performSelector:#selector(setTitleForViewController:) withObject:titleText];
} else destViewController.title = [[menuItems objectAtIndex:indexPath.row] capitalizedString];
} else destViewController.title = [[menuItems objectAtIndex:indexPath.row] capitalizedString];
}
I have used this code in prepareForSegue in other view controllers. The selector exists in the destination TableViewController, but SWRevealViewController passes over if-statement without executing.
I think the problem lies in the fact that you are trying to run a selector method on a UINavigationController and not the actual TableViewController in which the selector resides. Notice that destViewController is a UINavigationController, which has your TableViewController inside it.
So actually, you can try the following code and see if it works (I've tried this in a sample project using SWRevealViewController and it works)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Set the title of navigation bar by using the menu items
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
YourTableViewController *tableController = (YourTableViewController *)[destViewController childViewControllers].firstObject;
if ([segue.identifier isEqualToString:#"goalSegue"]) {
if ([tableController respondsToSelector:#selector(setTitleForViewController:)]) {
NSString * titleText = #"Athlete Goals";
[tableController performSelector:#selector(setTitleForViewController:) withObject:titleText];
} else destViewController.title = [[menuItems objectAtIndex:indexPath.row] capitalizedString];
} else destViewController.title = [[menuItems objectAtIndex:indexPath.row] capitalizedString];
}
As far as I understand, this may not exactly be a problem with SWRevealViewController.
Hope this helps.

Issue with PFObject

I need to pass a PFObject to 2 views, first one is detail and second is a segue from the detail. I can easily pass the PFObject to the detail, using PFObject *obj = [array objectAtIndex:indexPath.row], detailVC.object = object in prepareForSegue to a property of the detail view controller, but when I try to pass from the detail to the third view, using vc.object = self.object in prepareForSegue then the value of the PFObject in third view is nil. What is the problem?
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segue"]) {
thirdVC *vc = (thirdVC *)segue.destinationViewController;
vc.object = self.object;
}
}
I often found this error when I tried to segue to a VC embedded within its own navigation controller. Make sure it is not, and if it is use this to refer to the controller instead
if ([segue.identifier isEqualToString:#"<#Segue Name#>"]) {
UINavigationController *nav = (UINavigationController *)[segue destinationViewController];
<#UIViewController#> *controller = (<#UIViewController#> *)nav.topViewController;
controller.object = self.object;
}
Other than that, I can only think to log the object inside the second VC's prepareForSegue and see if it exists there

Failed to push to a View Controller in iOS

I'm a very beginner to iOS development. I made a navigation application in iOS to view some details in another view when table view cell tap. I did the following code,
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
LawyerViewController *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"LawyerViewController"];
NSLog(#"%#",[self.myObject objectAtIndex:indexPath.row]);
dvc.lawyer = [self.myObject objectAtIndex:indexPath.row];
[self.navigationController pushViewController:dvc animated:YES];
}
This is going to the next view. But dvc.lawyer is not null here. It's null on Next View page.
Reading the Value in Next page
NSLog(#"%#",self.lawyer.firstName);
How can I fix this.
Thanks in Advance!
You are supposed to instantiate ViewControllers in another way, if you use storyboard segues. You need to implement prepareForSegue where you can Access the segues destinationViewController like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// reference to the destination view controller
LawyerViewController *vc = [segue destinationViewController];
// Pass any data
vc.lawyer = self.myObject[[self.tableView indexPathForSelectedRow].row]; // Not tested
}
}

iOS Storyboard - Navigation Controller Not Working

I am having trouble with a Navigation Controller in my iOS project which uses Storyboards.
The main part of the project is a UITabBar. When the app loads for the very first time the screen RegisterViewController is presented:
When the user taps on the "Register" button a HTTP POST request is made, then upon receiving the response (JSON object) the screen QuestionnaireViewController is presented using:
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
QuestionnaireViewController *questionnaireViewController = [mainStoryboard instantiateViewControllerWithIdentifier:#"QuestionnaireView"];
[questionnaireViewController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[questionnaireViewController setQuestionsAndAnswers:_questionsAndAnswers];
[self presentViewController:questionnaireViewController animated:NO completion:nil];
When the user taps on a cell in QuestionnaireViewController a message is sent to prepareForSegue:sender:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UINavigationController *navigationController = segue.destinationViewController;
AnswersViewController *answersViewController = [[navigationController viewControllers] objectAtIndex:0];
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NSArray *answers = [[_questionsAndAnswers objectAtIndex:indexPath.row] objectForKey:#"answers"];
[answersViewController setAnswers:answers];
}
At this point the app crashes with an error of:
-[AnswersViewController viewControllers]: unrecognized selector sent to instance.
Below is a more comprehensive overview of my storyboard, which may help in understanding where I have gone wrong:
I am stumped as to how to fix this, and am hoping that someone out there is able to help.
Thanks,
Nick
First, you should present the navigation controller, not its root view controller. Then when you want to populate the root view controller with some data, you need to reference it as the navigation controller's root view controller:
UINavigationcontroller *questionnaireNavController = [self.storyboard instantiateViewControllerWithIdentifier:#"QuestionnaireNavigationController"];
[questionnaireNavController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
QuestionnaireViewController *qvc = (QuestionnaireViewController *)[questionnaireNavController topViewController];
[qvc setQuestionsAndAnswers:_questionsAndAnswers];
[self presentViewController:questionnaireNavController animated:NO completion:nil];
Second, in prepareForSegue:sender: you don't need to reference a navigation controller at all:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
AnswersViewController *answersVC = segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NSArray *answers = [[_questionsAndAnswers objectAtIndex:indexPath.row] objectForKey:#"answers"];
[answersVC setAnswers:answers];
}
You are not getting the navigationController properly. Instead of segue.destinationViewController, use self.navigationController
By calling segue.destinationViewController, you are getting a pointer to the VC you are segueing to (AnswersViewController) which doesn't understand the message viewControllers because it is not a UINavigationController.
Also the AnswersViewController is objectAtIndex:1 I believe, check this though.

Setting a property in prepareForSegue using a popover

I have a ViewController that has a couple of buttons on it created in Interface Builder. The first button will display a popover linked up in IB, it is linked to a UINavigationController and has a TableView under it with a class of PopupViewController.
The second button, I have an action setup for goToCategory and when clicking on that, I want to set a property on the PopupViewController
ViewController.m
//go to category
-(IBAction)goToCategory:(id)sender{
NSLog(#"GO TO CAT");
//PopupViewController *popupVC = [self.storyboard instantiateViewControllerWithIdentifier:#"popoverVC"];
//popupVC.currentLevel = 1;
[self performSegueWithIdentifier:#"popoverSegue" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSLog(#"seg1");
if ([[segue identifier] isEqualToString:#"popoverSegue"]){
//PopupViewController *popupVC = (PopupViewController *)[[segue destinationViewController] visibleViewController];
//PopupViewController *popupVC = [segue destinationViewController];
PopupViewController *popupVC=[[[segue destinationViewController]viewControllers]objectAtIndex:0];
popupVC.test = #"just a test";
NSLog(#"seg2");
}
}
PopupViewController.h
#property (nonatomic, strong) NSString *test;
PopupViewController.m
#synthesize test;
-(void)viewDidLoad{
NSLog(#"test: %#", test); //returns test: (null)
}
I've found a lot of answers on SO, hence some of the commented out lines in my prepareForSegue. But none of these set the value of test. PopupViewController *popupVC = [segue destinationViewController]; throws an error due to it referring to the UINavigationController so I can't use that as it is, even though that seems to be the way to do it in a lot of answers I've seen. But no matter which way I try doing it, the output is always null?
UPDATE:
PopupViewController *popupVC = (PopupViewController *)[[segue destinationViewController] visibleViewController]; and PopupViewController *popupVC=[[[segue destinationViewController]viewControllers]objectAtIndex:0]; from my prepareForSegue above both work on the 6.1 simulator. My iPad's iOS is 5.1.1 which it isn't working on. Is there something different I need to do for iOS 5?
Try this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"seg1");
if ([[segue identifier] isEqualToString:#"popoverSegue"])
{
UINavigationController *navController = (UINavigationController*)[segue destinationViewController];
PopupViewController *popupVC = [navController topViewController];
popupVC.test = #"just a test";
NSLog(#"seg2");
}
}

Resources