Segue With NSUserDefaults + NSCoder Object - ios

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ShowWordDetailsTwo"]) {
NSIndexPath *indexPath = nil;
Words *word = nil;
indexPath = [self.tableView indexPathForSelectedRow];
word = [myFavsTwo objectAtIndex:indexPath.row];
DetailsViewController *destViewController = segue.destinationViewController;
destViewController.word = word;
}
}
I'm getting a crash on segue -- breakpoint at:
destViewController.word = word;
but if I "continue" on my debugger everything will work as normal -- the app just seems to be getting hung up on this line...
I think it's got to do with my object being part of NSUserDefaults with NSCoder...
how can I make it so that the app doesn't crash?!
I'm not getting any error message just a break point error

Just clarifying,
Did you create the breakpoint yourself, or was it autocreated by the debugger?
Try disabling the breakpoint to see if it works.

Related

why does my prepareForSegue Crash

I am trying to pass in IndexPath through a segue though a navigationController, but it crashes on line:
view.selectedAccount = self.selectedAccountRow;
thanks
-(IBAction)changeButtonPressed:(id)sender {
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.accountTableView];
NSIndexPath *indexPath = [self.accountTableView indexPathForRowAtPoint:buttonPosition]
self.indexPath = indexPath;
NSLog(#"%ld",(long)indexPath.row);
}
and
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[super prepareForSegue:segue sender:sender];
ViewController2 *view = [segue destinationViewController];
view.selectedAccount = self.indexPath;
}
answer here: Set NSString Object, prepareForSegue through UINavigationController
I see many errors:
self.selectedAccountRow never gets defined, change to this:
-(IBAction)changeButtonPressed:(id)sender {
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.accountTableView];
NSIndexPath *indexPath = [self.accountTableView indexPathForRowAtPoint:buttonPosition]
self.selectedAccountRow = indexPath;
}
When using [segue destinationViewController] you need to ensure that the class your assingning is the right one:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ViewController2 *view = (ViewController2*)[segue destinationViewController];
view.selectedAccount = self.selectedAccountRow;
}
There's no need to declare the as strong, as it is the default one, but it's recommender as it's easier to read, and it's a good coding practice.
#property (strong, nonatomic) NSIndexPath *selectedAccount;
You need to name better your classes and properties, if you declare a viewController subclass, the name should be self explanatory, maybe you can name it detailViewController instead on viewController2.
Also, you should consider using a 2-3 letters prefix for your classes, please read good obj-c practices in here:
Objective-C Good practices
Right click on your view in IB and remove and instances where there is a yellow warning sign. Run and everything should work.

Prepare for segue crashing at isKindOfClass comparison

My prepare for segue call keeps causing a crash without any error message. So I use NSLog to track what’s happening. The following line is never reached
NSLog(#"The VCs matched!!: " )
Here is the method
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"enter prepare for segue.");
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
if ([segue.identifier isEqualToString:SegueIdentifierA]) {
NSLog(#"Destination to match are: %#, %# .",segue.destinationViewController,[PaperDetailViewController class] );
if ([segue.destinationViewController isKindOfClass:[PaperDetailViewController class]]) {
NSLog(#"The VCs matched!!: " );
PaperDetailViewController *paperDetailView = (PaperDetailViewController *)segue.destinationViewController;
}else NSLog(#"NO ONO NO match for %# AND %#.",segue.destinationViewController,[PaperDetailViewController class] );
}
NSLog(#"exit prepare for segue.");
}
It would be great to see the stack trace as the comments suggest. That would provide valuable clues. Without them, the most likely culprit is:
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
Which is blindly assuming that the sender is a UITableViewCell. If it isn't, you'd see a crash for sure (and we'd see it in the stack trace). If a table selection is what's triggering the segue, than this is safer and easier to read...
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Given the information all I can recommend is that you specify the class for your view controller in the storyboard editor.
Sorry for the false alarm. There seems to have been a problem with my Xcode. Xcode just crashed and after I restarted it, everything just work as expected. Thanks and +1 to everyone for helping.

View Controllers giving an error when creating a segue

I have a navigation controller and the first VC modals into the second one fine. I pressed ctrl+button and dragged it over, all works fine.
I am doing a second segue from the first VC (again) and this time its another button, I am ctrl+button and dragging it to the new VC and I get an USELESS error in XCODE -
2014-03-04 11:57:21.340 OutTonight[3173:60b] -[SettingsViewController
setDealdetail:]: unrecognized selector sent to instance 0x16e686d0
2014-03-04 11:57:21.342 OutTonight[3173:60b] * Terminating app due
to uncaught exception 'NSInvalidArgumentException', reason:
'-[SettingsViewController setDealdetail:]: unrecognized selector sent
to instance 0x16e686d0'
* First throw call stack:
Here is my prepareforseguecode
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableview indexPathForSelectedRow];
DealViewController *detailView = (DealViewController *)segue.destinationViewController;
detailView.dealdetail = [self.allcontent objectAtIndex:indexPath.row];
detailView.dealpostcode = [self.allpostode objectAtIndex:indexPath.row];
detailView.dealvenuename = [self.allname objectAtIndex:indexPath.row];
detailView.dealaddress = [self.alladdress objectAtIndex:indexPath.row];
detailView.dealaddress2 = [self.alladdress2 objectAtIndex:indexPath.row];
detailView.deallat = [self.alllat objectAtIndex:indexPath.row];
detailView.deallng = [self.alllong objectAtIndex:indexPath.row];
detailView.userlatitude = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLatitude"];
detailView.userlongitude = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLongitude"];
}
Any ideas?
I assume you have done something in -prepareForSegue: for the original segue? In which case, you need to make sure you are checking which segue it is in -prepareForSegue:, and doing the correct thing for each one.
Edit:
To expand on my answer, I guess you are using segue.destinationViewController, and calling setDealdetail: on it. This probably worked fine for your initial segue, because the destinationViewController responded to that message, but, the destination for the new segue doesn't. You need to check which segue is being performed. Using [segue.identifier isEqualToString:MySegueIdentifierString];
Edit 2 (after posting code):
Ok, you need to check which segue is being performed in your -prepareForSegue:. Something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:SegueToDealViewControllerIdentifier]) {
NSIndexPath *indexPath = [self.tableview indexPathForSelectedRow];
DealViewController *detailView = (DealViewController *)segue.destinationViewController;
detailView.dealdetail = [self.allcontent objectAtIndex:indexPath.row];
detailView.dealpostcode = [self.allpostode objectAtIndex:indexPath.row];
detailView.dealvenuename = [self.allname objectAtIndex:indexPath.row];
detailView.dealaddress = [self.alladdress objectAtIndex:indexPath.row];
detailView.dealaddress2 = [self.alladdress2 objectAtIndex:indexPath.row];
detailView.deallat = [self.alllat objectAtIndex:indexPath.row];
detailView.deallng = [self.alllong objectAtIndex:indexPath.row];
detailView.userlatitude = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLatitude"];
detailView.userlongitude = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserLongitude"];
}
}
Where SegueToDealViewControllerIdentifier is the segue identifier for the original segue.

UITableView only sending data to Detail View Controller on Second Try

Hey there I have been working on a transit app for some time and have been stuck with this issue for a while now.
I am using iOS 5 and a storyboard. Basically I have a UITableView that displays favorite bus stop locations, when a user selects a row I use:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Favorite *favorite = [self.favoriteItems objectAtIndex:indexPath.row];
stopString = favorite.title;
routeString = favorite.subtitle;
}
With the stop and route information of the cell the user chose I then prepare for a segue that corresponds to a segue on my storyboard, pushing a detail view controller that uses the stop name and route name to display times from a plist.
I am fairly new to Objective C and iOS so I am using a segue that my friend told me would work, however, it might be the problem. The segue looks like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destination = segue.destinationViewController;
if ([destination respondsToSelector:#selector(setDelegate:)])
{
[destination setValue:self forKey:#"delegate"];
}
if ([destination respondsToSelector:#selector(setSelection:)])
{
NSString *route = routeString;
NSDictionary *selection1 = [NSDictionary dictionaryWithObjectsAndKeys:route, #"route", stopString, #"stop", nil];
[destination setValue:selection1 forKey:#"selection"];
}
}
After the segue in my DetailViewController I grab the stop and route information in the view DidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
route = [selection objectForKey:#"route"];
stopName = [selection objectForKey:#"stop"];
NSLog(#"stopName: %#", stopName);
NSLog(#"routeName: %#", route);
}
Here is where my problems arise. When I run the simulator and click on an a cell in my table view, I am pushed to the DVC, however, the stopName and routeName are both null, so no information was sent or received. BUT, if I go back to the table and click another cell, the routeName and stopName are filled with the information that should have sent the first time I clicked a cell. If I continue this process it continues to send the information for the cell tapped previously, not currently.
So basically information is sending but only after I go through the segue twice. Obviously I want it to send the information and receive it the first time, but it is delayed and driving me nuts. I appreciate any help someone can give me as I have been searching the internet for days now trying to fix this issue, thank you so much in advance for any assistance!
prepareForSegue: is being called before didSelectRowAtIndexPath:. This is why the values you see always are lagging behind.
The better solution is to get the stopString and routeString values in your prepareForSegue: method (and not use didSelectRowForIndexPath: at all). The key to doing this is to realize that the sender parameter value being passed to prepareForSegue: is the UITableViewCell that was tapped. You can use the UITableView method indexPathForCell to get the cell's indexPath in your table, and then use that to look up the data in your favoriteItems array.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UITableViewCell *cell = (UITableViewCell*)sender;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
Favorite *favorite = [self.favoriteItems objectAtIndex:indexPath.row];
stopString = favorite.title;
routeString = favorite.subtitle;
UIViewController *destination = segue.destinationViewController;
if ([destination respondsToSelector:#selector(setDelegate:)])
{
[destination setValue:self forKey:#"delegate"];
}
if ([destination respondsToSelector:#selector(setSelection:)])
{
NSString *route = routeString;
NSDictionary *selection1 = [NSDictionary dictionaryWithObjectsAndKeys:route, #"route", stopString, #"stop", nil];
[destination setValue:selection1 forKey:#"selection"];
}
}
Make sure that you are NOT connecting the segue to the next view controller to the tableView CELL directly. Connect to the whole UITableViewController / UIViewController (whichever you are using) and give a name, say "segueNameInStoryboard".
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Favorite *favorite = [self.favoriteItems objectAtIndex:indexPath.row];
stopString = favorite.title;
routeString = favorite.subtitle;
/* add this line */
[self performSegueWithIdentifier:#"segueNameInStoryboard" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"segueNameInStoryboard"])
{
UIViewController *nextViewController = segue.destinationViewController;
nextViewController.delegate = self;
NSDictionary *selection1 = [NSDictionary dictionaryWithObjectsAndKeys:routeString, #"route", stopString, #"stop", nil];
nextViewController.selection = selection1;
}
}

Retrieving data from object

I am very new to developing in iOS. I am trying to pass some data through a segue in a table view. Here is what I am calling to pass the data:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"ShowContactDetails"]) {
ContactDetailsViewController *dvc = [segue destinationViewController];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
Contact *c = [jsonResults objectAtIndex:path.row];
[dvc setSelectedContact:c];
}
}
It passes fine and when I do a NSLog on selectedContact, this is what I get:
2012-05-21 15:15:42.410 Test[8352:f803] {
category = Prospect;
id = 19895;
label = "John Doe";
}
The problem is, I don't know how to access those items individually. I have tried to call things like objectForKey but I get an error.
From the output of your NSLog, selectedContact seems to be an NSDictionary object. Try using [selectedContact valueForKey] instead of [selectedContact objectForKey].
For example:
NSLog(#"Name: %#", [selectedContact valueForKey:#"label"]);

Resources