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"]);
Related
I've got a tableview setup to display data from an sqlite database, now what I am trying to do is setup a view to display further information from said database when the user clicks on a table cell.
From what I've read so far my understanding that this is done mainly in the prepareForSegue method inside the table view's controller?
Anyway, after a lot of googling I've ended up with this from an AppCoda tutorial (link)...
if([segue.identifier isEqualToString:#"pushToMountainInfo"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *nav = segue.destinationViewController;
MountainInformation *destViewController = [nav.viewControllers objectAtIndex:0];
MountainsObject *mountain = [self.mountains objectAtIndex:indexPath.row];
destViewController.nameLabel = mountain.name;
NSLog(#"%#", mountain.name);
}
I put the NSLog there to test, and it does output the mountain's name to the log but the label remains blank when I run the app.
Can anybody please help?
Thanks..!
Okay to shorten your code a bit..
if([segue.identifier isEqualToString:#"pushToMountainInfo"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
MountainInformation *destViewController = [segue destinationViewController];// do this only if your segue is connected to the next one from previous, or else let it stay as you have, only change the later part
MountainsObject *mountain = [self.mountains objectAtIndex:indexPath.row];
destViewController.myMountain = mountain.name;
NSLog(#"%#", mountain.name);
}
Now create a property in MountainInformation.h file
#property (nonatomic, strong) NSString* myMountain;
Now your property is set to the name you want to set.
Now in viewDidLoad in MountainInformation.m
-(viewDidLoad){
self.labelToShowName.text = self.myMountain;
}
Hope this helps
[EDIT]
In MountainInformation.h Import your mountain class.
#import "MountainObject.h"
Change the property to
#property(nonatomic, strong) MountainObject *selectedMountain
Now in previous view controller.
if([segue.identifier isEqualToString:#"pushToMountainInfo"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *nav = segue.destinationViewController;
MountainObject *mountain = [self.mountain objectAtIndex.indexPath.row];
destViewController.selectedMountain = mountain;
}
In MountainInformation.h
-viewDidLoad{
NSString *mountainName = self.selectedMountain.name;
NSString *mountainRegion =self.selectedMountain.region;
NSString *mountainHeight =self.selectedMountain.height;
//and other properties. and then you can set it to a single label by using
self.myLabel.text = [NSString stringWithFormat:#" Name - %#, Height- %#, Region- %#",mountainName, mountainHeight, mountainRegion];
}
I have the following code which works out which section/data index to pass to a destination controller based on the clicked cell.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
self.selectedItIndex = indexPath.row; // define NSInteger selectedItemIndex property in your interface
self.selectedSection = indexPath.section;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"sightSeg"]) {
NSString *s = self.sectionData[_selectedSection];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"siteSection like %#", s];
NSArray *filteredArr = [self.sightsArray filteredArrayUsingPredicate:pred];
NSLog(#"Value of hello = %#", filteredArr);
sightsObject *rightS = filteredArr[_selectedItIndex];
_finNo = _selectedItIndex +=1;
NSLog(#"balls = %#",rightS );
SightViewController *destController = (SightViewController *)segue.destinationViewController;
destController.viewTit = rightS.siteTitle;
}
}
The code works fine first try (as in the correct data is passed relevant to the cell/section clicked) - the issue I have is that if you return to the parent controller and select another cell - the same information is passed again - if you repeat the process selecting a 3rd cell - the data for the second cell clicked is passed - so its as though its a step out of sync!?
Can anyone offer any advice? - Is there a way to only run the sgue code once the values have been set in the didselectpath method?
The sender parameter in prepareForSegue will be the collection view cell you've tapped. Use the following code to derive your index at the point of sending:
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForCell:sender];
You don't need the code in didSelectItem...
Try calling [collectionView indexPathsForSelectedItems] inside prepareForSegue: to get the index path instead of saving it off in collectionView:didSelectItemAtIndexPath:
- (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.
In my tableView I have a button on the nav bar to add a new core data entry. This works fine and the new entry is added to core data and at the top of the tableView. Then if I select the entry (or any entry) in the tableView, I have a seque that transitions to a new view controller showing the details of that core data item. That works fine too.
But I'd like to change how I add entries. I'd like to push the same button in the nav bar and I'd still like the new entry added to the table. But at the same time I want to transition to the detail view controller AND show the just created values for the entry I just made.
As you can see from the code below, the seque to view game details simply grabs the row that was selected and passes it to the detail view controller. In my prepareForAddGameDetailSegue I tried to cheat by just setting the indexPath to 0 for the newly created entry where the new entry is inserted. That doesn't work and I have a feeling it's because my fetchedResultsController isn't updated before the transition.
So when the detail view controller loads values for the newly created game are null. But if I go back to the tableView and then select the row where that new game was just inserted, it'll transition fine and the details will all show.
Anyone help on what step I'm doing wrong? Thanks!
Here are the segue handlers:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showGameDetails"]) {
[self prepareForGameDetailSegue:(UIStoryboardSegue *)segue sender:(id)sender];
return;
}
if ([[segue identifier] isEqualToString:#"addGameDetails"]) {
[self prepareForAddGameDetailSegue:(UIStoryboardSegue *)segue sender:(id)sender];
return;
}
}
- (void)prepareForGameDetailSegue:(UIStoryboardSegue*)segue sender:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Game *SelectedGame = (Game *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
//pass the selected game to the new view controller
GameDetailViewController *detailViewController = (GameDetailViewController *)[segue destinationViewController];
detailViewController.title = [NSString stringWithFormat:#"Game Details"];
detailViewController.game = SelectedGame;
[detailViewController updateInterface];
}
- (void)prepareForAddGameDetailSegue:(UIStoryboardSegue*)segue sender:(id)sender {
[self addGame];
Game *newGame = (Game *)[[self fetchedResultsController] objectAtIndexPath:0];
GameDetailViewController *detailViewController = (GameDetailViewController *)[segue destinationViewController];
detailViewController.title = [NSString stringWithFormat:#"New Game"];
detailViewController.game = newGame;
[detailViewController updateInterface];
}
Here's the addGame method:
-(void)addGame {
Game *newGame = (Game *)[NSEntityDescription insertNewObjectForEntityForName:#"Game"
inManagedObjectContext:_managedObjectContext];
NSDate *today = [NSDate date];
newGame.gameDate = today;
newGame.points = 600;
newGame.seconds = [NSNumber numberWithInt:10];
NSError *error = nil;
if (![_managedObjectContext save:&error]) {
NSLog(#"Error in adding a new game %#, %#", error, [error userInfo]);
abort();
}
}
change the signature of -(void)addGame to -(Game*)addGame and return the newly saved game.
use the object returned to load your detail view.
later, in the return segue, find the index of the newly inserted object and select it.
You can use: - (NSIndexPath *)indexPathForObject: method of the FRC to get the IndexPath.
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;
}
}