[UINavigationController setGoalName:]: unrecognized selector sent to instance 0x7964e2c0 - iphone

I have created the app with following code. Its working fine with iOS7 but it throws the below error when I run with iOS8.
[UINavigationController setGoalName:]: unrecognized selector sent to instance 0x7964e2c0
My firstViewcontroller.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
GoalDetailsViewController *goalsDetailsViewController = segue.destinationViewController;
NSLog(#"%#",[NSString stringWithFormat:#"%#", [[self.arrCategoryTitle objectAtIndex:indexPath.row] objectAtIndex:indexOfCategory]]);
goalsDetailsViewController.goalName = #"Exercise Daily";
}
My GoalDetailsViewController.h
#interface GoalDetailsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic) NSString *goalName;
Thanks in advance.

Seems like your destinationviewcontroller is a subclass of UINAvigationController.
Try this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
GoalDetailsViewController *goalsDetailsViewController = [(UINavigationController*)segue.destinationViewController topViewController];
NSLog(#"%#",[NSString stringWithFormat:#"%#", [[self.arrCategoryTitle objectAtIndex:indexPath.row] objectAtIndex:indexOfCategory]]);
goalsDetailsViewController.goalName = #"Exercise Daily";
}

The easiest way to handle this crash would be to simply make sure that the destinationViewController is of the type you're expecting before you attempt to set a property on it. Something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
GoalDetailsViewController *goalsDetailsViewController = segue.destinationViewController;
NSLog(#"%#",[NSString stringWithFormat:#"%#", [[self.arrCategoryTitle objectAtIndex:indexPath.row] objectAtIndex:indexOfCategory]]);
if ([segue.destinationViewController isKindOfClass:[GoalDetailsViewController class]]) {
GoalDetailsViewController *goalsDetailsViewController = segue.destinationViewController;
goalsDetailsViewController.goalName = #"Exercise Daily";
}
}
This change ensures that the destinationViewController is of kind GoalDetailsViewController before treating it as such.

Related

Passing data between two controllers using storyboards

I am trying to pass data from one UITableViewController to another. This is my code in the initial view controller:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Subject *subject = (Subject *)[self.fetchedResultsController objectAtIndexPath:indexPath];
[self showList:subject animated:YES];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)showList:(Subject *)subject animated:(BOOL)animated {
ListsViewController *lists = [[ListsViewController alloc] initWithStyle:UITableViewStyleGrouped];
lists.subject = subject;
NSLog(#"%#", lists.subject);
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
The log output was showing that it had the data I wanted had been passed over. However when I perform the segue and log the subject in the ListsViewController is shows null.
Any ideas?
You need to overwrite prepareForSegue:sender: method. The quick fix would be
- (void)showList:(Subject *)subject animated:(BOOL)animated
{
[self performSegueWithIdentifier:#"showDetail" sender:subject];
}
...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showDetail"]) {
ListsViewController *controller = ([segue.destinationViewController isKindOfClass:[ListsViewController class]]) ? segue.destinationViewController : nil;
controller.subject = ([sender isKindOfClass:[Subject class]]) ? subject : nil;
}
}
The reason why your code did not work is that in your showList:animated: method you created a ListsViewController instance and assigned it a subject, but this view controller was never presented. Instead performSegueWithIdentifier:sender creates another instance of your ListsViewController class which knows nothing about your subject. That's why you need to wait for UIStoryboardSegue to instantiate a destination view controller from the storyboard and then configure it the way you want, which you can do in prepareForSegue:sender: method.
Also it might be not the best idea to use subject as a sender in performSegueWithIdentifier:sender method, because it's just not the sender :). What I would do is create a property subject in your view controller class and use it prepareForSegue:sender:
#interface MyViewController ()
#property (strong, nonatomic) Subject *subject;
#end
#implementation MyViewController
- (void)showList:(Subject *)subject animated:(BOOL)animated
{
self.subject = subject;
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showDetail"]) {
ListsViewController *controller = ([segue.destinationViewController isKindOfClass:[ListsViewController class]]) ? segue.destinationViewController : nil;
controller.subject = self.subject;
}
}
...
#end
Implement prepareForSegue and pass date in this methos
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([seque.identifier isEqualToString:#"showDetail"])
{
ListsViewController *lists = seque.destinationViewController;
lists.subject = subject;
}
}
That's good, but now you need to add this:
First instead of:
[self performSegueWithIdentifier:#"showDetail" sender:self];
You need to send the object:
[self performSegueWithIdentifier:#"showDetail" sender:subject];
Add a property in your ListsViewController.h:
#property (nonatomic, strong) Subject * subjectSegue;
And now in your first view controller:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showDetail"]) {
ListsViewController * lists = (ListsViewController *)[segue destinationViewController];
lists.subjectSegue = sender;
}
You need to understand that performSegueWithIdentifier:sender: creates a new instance of view controller. So the ListsViewController that you have created is not the being displayed on the screen.
You need to override `prepareForSegue:sender:
- (void)showList:(Subject *)subject animated:(BOOL)animated
{
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showDetail"]) {
ListsViewController *controller = (ListsViewController *)segue.destinationViewController;
controller.subject = self.subject;
}

UITableViewController unrecognized selector sent to instance

I have a tableviewcontroller and a detailtableviewcontroller when I pass an integer I get
-[UITableViewController setSurveyNumber:]: unrecognized selector sent to instance
Bizard thing is exact same code works for tableviewcontroller to -> uiviewcontroller
table -> table code
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"pushSurveyDetails"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSInteger row = [indexPath row];
SurveyDetailViewController *surveyController = [segue destinationViewController];
surveyController.surveyNumber=row;
}
}
in SurveyDetailViewController.h
#interface SurveyDetailViewController : UITableViewController
{
}
#property int surveyNumber;
#end
SurveyDetailViewController.m
#implementation SurveyDetailViewController
#synthesize surveyNumber;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Survey Number is %i",surveyNumber);
}
why this error occurs?
The error message indicates that [segue destinationViewController] returns a UITableViewController and not a SurveyDetailViewController as expected.
The controller class can be set in the storyboard file.

passing value to destination controller

I am passing ID from UITABLEVIEWCONTROLLER to another UITABLEVIEWCONTROLLER but it throw the following error.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITabBarController setCityId:]: unrecognized selector sent to instance 0x75225e0'
here us the prepareForSegue function:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"cityPushToTab"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
featuredViewController *destViewController = segue.destinationViewController;
destViewController.cityId = [productKeys objectAtIndex:indexPath.row];
}
}
the function did well before i call the cityId of featured controller. I have tried to logg the productKeys which print the correct values but it is terminating when I try to assign value to destination view controller object. please help.
Are you sure destViewController is of class featuredViewController ? I'm sure it's not. The crash log tells it's a UITabBarController.
What I recommend is create a class that inherits from UITabBarController. I'll call it MyTabBarViewController. Set the class of your tab bar controller in your storyboard to this new class.
In MyTabBarViewController.h, create a property :
#property (nonatomic, strong) id cityId;
(note that cityId can be of any type you need, e.g. NSString, NSNumber, ...).
Then, change your prepareForSegue code :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"cityPushToTab"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
MyTabBarViewController *destViewController = segue.destinationViewController;
destViewController.cityId = [productKeys objectAtIndex:indexPath.row];
}
}
Next, in the .m files of the 4 view controllers that are in your tab bar, you can use this code to access cityId :
// Cast the viewcontroller's tab bar to your class
MyTabBarViewController *tabBarController = (MyTabBarViewController*)self.tabBarController;
// Access your property
id cityId = tabBarController.cityId;
// You can test to see if it works by casting to an NSString and NSLog it
NSString *cityIdString = (NSString*) tabBarController.cityId;
NSLog (#"%#", cityIdString);

saving/sharing a String in xcode

i need to save a string within my application but i dont want to create a plist just for saving 1 string is there any other way to do so? im using storyboard. i tried segue but it didn't work
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString: #"modal"])
{
ViewController *vc = (ViewController *)[segue destinationViewController];
vc.subject = self.subject;
}
}
What do you mean by "I need to save a string within my applicaion"? Do you just want to pass the string to your destination ViewController?
If that's the case, you could define a new property in your destination ViewController (assuming you know which one it is)
#property (nonatomic, strong) NSString *myProperty;
And then
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString: #"modal"])
{
[segue.destinationViewController setMyProperty:self.myProperty];
}
}
If you want your string to be accessible from anywhere in the application, you can save it to the user defaults quite easily :
[[NSUserDefaults standardUserDefaults]setObject:myProperty forKey:#"myPropertyKeyName"];
You can get it back later :
NSString *mySavedProperty= [[NSUserDefaults standardUserDefaults]stringForKey:#"myPropertyKeyName"];
If u can to use the string any where in the project just create a extern variable like this way.
In AppDelegate.h
extern NSString *stringObject;
In AppDelegate.m
NSString *stringObject;
U can use the stringObject any where in the project.

How To Use Storyboard?

I'm trying to use storyboards segue instead of didSelectRowAtIndex.
This is what I have, but this method does not recognize indexPath.row. Is there an alternative I can use to do the same thing?
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SpecificExerciseTableViewController *upcomingViewController = segue.destinationViewController;
if ([segue.identifier isEqualToString:#"Web"])
{
upcomingViewController.exerciseArray = [[self.muscleArray objectAtIndex:indexPath.row]objectForKey:#"exercises"];
upcomingViewController.muscleName = [[self.muscleArray objectAtIndex:indexPath.row]objectForKey:#"muscleName"];
}
}
Unless you have that indexPath as an ivar, no such variable exists in the scope.
If you would like to get the indexPath for the selected row in a UITableView use:
- (NSIndexPath *)indexPathForSelectedRow
The adjusted code for above:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
SpecificExerciseTableViewController *upcomingViewController = segue.destinationViewController;
if ([segue.identifier isEqualToString:#"Web"])
{
upcomingViewController.exerciseArray = [[self.muscleArray objectAtIndex:indexPath.row]objectForKey:#"exercises"];
upcomingViewController.muscleName = [[self.muscleArray objectAtIndex:indexPath.row]objectForKey:#"muscleName"];
}
}
This trick works fine,heres an example of how I used it to pull parsed elements into a web view
.h file
#property (strong, nonatomic) NSString *url;
#property (strong, nonatomic) UIWebView *webView;
.m file
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
if ([segue.identifier isEqualToString:#"WebViewSegue"]) {
WebViewController *webViewController = segue.destinationViewController;
webViewController.url = (self.parseResults)[indexPath.row][#"link"];
webViewController.title = (self.parseResults)[indexPath.row][#"title"];
}
}