Retrieving UITableViewCell Label Values For Passing To Modal Edit View - objective-c

I am trying to pass existing attribute values for a managed object, to a modal segue view for editing. From "editing mode," I'm going from a UITableViewController subclass (BreadRackTableViewController), using a modal segue to a UIViewController subclass (EditBreadRackTableViewController) by means of an embedded UINavigationController. Normal TableViewCell selection pushes to another UITableViewController subclass, but that's not important for the time being.
I've added properties to my editing view controller header (and #synthesized), to function as getters:
#property (nonatomic, strong) id existingBreadRackDataName;
#property (nonatomic, strong) id existingBreadRackDataDetails;
What I'm trying to do is populate the edit view's fields with the existing Core Data Entity Attributes, which would have been previously set by the user (in theory). I can get the data to show up if I pass along a literal string value, but I need to retrieve and pass the existing data.
Here's what I have currently:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"editBreadRackSegue"])
{
EditBreadRackTableViewController *ebrtvc = (EditBreadRackTableViewController *)[segue destinationViewController];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
BreadRackClass *breadRackClass = [[self fetchedResultsController]objectAtIndexPath:indexPath];
// [ebrtvc setBreadRackClass:breadRackClass];
ebrtvc.existingBreadRackDataName = breadRackClass.breadRackDataName;
ebrtvc.existingBreadRackDataDetails = [breadRackClass valueForKey:#"breadRackDataDetails"];
}
}
These last two lines of code...
ebrtvc.existingBreadRackDataName = breadRackClass.breadRackDataName;
ebrtvc.existingBreadRackDataDetails = [breadRackClass valueForKey:#"breadRackDataDetails"];
...they both return nil. If I specify a literal string though, that literal string shows up where it needs to.
All of that said, my question is:
How do I retrieve the attribute's key value for that selected row (or just the textLabel and detailTextLabels), and assign it to my setter?
Solution:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"editBreadRackSegue"])
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
BreadRackClass *breadRackClass = [[self fetchedResultsController]objectAtIndexPath:indexPath];
[segue.destinationViewController setExistingBreadRackDataName:[breadRackClass valueForKey:#"breadRackDataName"]];
[segue.destinationViewController setExistingBreadRackDataDetails:[breadRackClass valueForKey:#"breadRackDataDetails"]];
}
// code for other segues here...
}
I ended up removing the ebrtv variable, and cleaned up the code a little bit. What worked though, was using the indexPathForCell:sender instead of indexPathForSelectedRow when declaring my indexPath for breadRackClass.

I think the indexPathForSelectedRow could be a problem.
You can just pass the indexPath from the didSelectRowAtIndexPath to the prepareForSegue , like:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"editBreadRackSegue" sender:indexPath];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"editBreadRackSegue"])
{
NSIndexPath *clickedIndexPath = (NSIndexPath*)sender;
if( [clickedIndexPath isKindOfClass:[NSIndexPath class]] ){
BreadRackClass *breadRackClass = [[self fetchedResultsController]objectAtIndexPath:clickedIndexPath];
EditBreadRackTableViewController *ebrtvc = (EditBreadRackTableViewController *)[segue destinationViewController];
ebrtvc.existingBreadRackDataName = breadRackClass.breadRackDataName;
ebrtvc.existingBreadRackDataDetails = [breadRackClass valueForKey:#"breadRackDataDetails"];
}
}
}
Let me know if it works for you.

Related

How to set destination view controller using indexpath value?

I have a collection view controller if the user select any cell means its need to go destination view controller.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
cell=[collectionview cellForItemAtIndexPath:indexNumberStorager];
NSInteger indexnum;
indexnum=indexNumberStorager.row;
switch (indexnum) {
case 1:
if ([segue.identifier isEqualToString:#"Car"])
{
CarCleaningVC *dest = [segue destinationViewController];
}
break;
default:
break;
}
i tried using this code but not working properly please help me to find out the problem.
sender here is the cell that has been selected by the user (if the segue is on cell selection). You don't need to store indexPath anywhere.
Simply typecast sender into UICollectionViewCell(or your subclass if you're using any), and call indexPathForCell: on your collection view to get the indexPath.
Sample code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSUInteger indexNum = [self.collectionView indexPathForCell:(UICollectionViewCell*)sender].row;
switch (indexNum)
// Relevant code
}
Also, instead of depending on the segue identifier, try to use the destinationViewController's class:
if ([segue.destinationViewController isKindOfClass:[CarCleaningVC class]]) {
//relevant code
}
You can do something like this-
in your cellForItemAtIndexPath method, set the cell tag. Something like-
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.tag=indexPath.row;
return cell;
}
And then when you cast your sender to a cell, you can just access its tag which is your Collection View's Indexpath.row.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UICollectionViewCell *cell=(UICollectionViewCell*)sender;
NSInteger indexnum;
indexnum=cell.tag;
switch (indexnum) {
case 1:
if ([segue.identifier isEqualToString:#"Car"])
{
CarCleaningVC *dest = [segue destinationViewController];
}
break;
default:
break;
}

How to get the selected section in a UITableView

I have a HistoryTableViewController with 2 sections hooked up to a detail view controller. I want to be able to display the text and subtitle text from the HistoryTableViewController in the details view, but I want to make sure that it detects the right section. I know somewhere along the line I'll have this:
if (section == 0)
{
labelCellNum.text = Whatever was the main text in the selected table view cell
labelDueDate.text = Whatever was in the subtitle text in the selected table view cell
}
else if (section == 1)
{
labelCellNum.text = Whatever was the main text in the selected table view cell
labelDueDate.text = Whatever was in the subtitle text in the selected table view cell
}
Since I'm displaying this on a details view controller, I don't know how to get the section from the TableViewController I'm getting displayed from. I pretty much need to know how to get the section, and the main text + subtitle text.
OK Perhaps I wasn't clear enough. This code is going in my ViewDidLoad of my DetailsViewController. NOT in my tableviewcontroller.
Here is the HistoryTableviewController code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// HistoryDetailsViewController *HDV = [self.storyboard instantiateViewControllerWithIdentifier:#"HistoryDetails"];
// [self.navigationController pushViewController:HDV animated:YES];
NSLog(#"index path section--%i",[indexPath section]);
[self performSegueWithIdentifier:#"Push" sender:indexPath];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"Push"]) {
HistoryDetailsViewController *detailVC=(HistoryDetailsViewController*)segue.destinationViewController;
detailVC.labelCellNum.text = #"Cell test";
detailVC.labelDueDate.text = #"Date Test";
}
}
And below is the code of my detailsViewController:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
labelCellNum.text = #"This isnt even getting called.";
}
check this , its simple
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"index path section--%i",[indexPath section]);
[self performSegueWithIdentifier:#"Push" sender:indexPath];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"Push"]) {
DetailViewController *detailVC=(DetailViewController*)segue.destinationViewController;
detailVC.title=#"value to pass";
}
}
There you go!
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Selected item infos
//
int section = indexPath.section;
int row = indexPath.row;
NSLog(#"section: %d / row: %d", section, row);
}
I assume you have a segue from the HistoryVC to the details VC. So you can pass the data across to the details VC in the prepareForSegue method in the HistoryVC. In the code fragment below, I am passing the cell title over into the new VC to set it's title. You could set other properties in the target VC, to suit your needs.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// get selected row's cell
//
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
// set desitination VC title
//
UIViewController *vc = [segue destinationViewController];
vc.navigationItem.title = cell.textLabel.text;
}

NSIndexPath 2 indicies

I'm doing something that involves a collection view with photos in it, and upon selecting one of the cells, it will segue into a new view where it shows a larger image.
Heres prepare for segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"showPhotoSegue"]) {
NSIndexPath *ip = [self.photoCollectionView indexPathForCell:sender];
PhotoDisplayViewController *viewController = segue.destinationViewController;
Photo* photo = [self.fetchedResultsController objectAtIndexPath:ip];
NSLog(#"setting PHOTO at indexPath %#", ip);
[viewController setPhoto:[UIImage imageWithContentsOfFile:photo.url]];
}
}
And heres didSelectItemAtIndexPath
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
NSString *identifier = #"showPhotoSegue";
[self performSegueWithIdentifier:identifier sender:self];
NSLog(#"Selected item at %#", indexPath);
}
My view is always empty so i added the print line statements, and it seems the output is always something like
Selected cell at <NSIndexPath 0x1e084940> 2 indexes [0, 0], detail view controller
So my question is, why is NSIndexPath always a pair of 2 indicies, and also how do i use it in my prepareforsegue to set the view for the segue
Thanks
In prepareForSegue:sender:, you expect sender to be a UICollectionViewCell.
In collectionView:didSelectItemAtIndexPath:, you are passing self (your UICollectionViewDelegate) as the sender argument. I suspect your collection view delegate is not a collection view cell.
Instead of sending the collection view delegate as sender, and expecting to receive a cell as sender, why not pass the index path as sender and expect to receive it as sender?
static NSString const *kShowPhotoSegueIdentifier = #"showPhotoSegue";
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:kShowPhotoSegueIdentifier sender:indexPath];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:kShowPhotoSegueIdentifier]) {
[self prepareForShowPhotoSegue:segue withIndexPath:sender];
}
}
- (void)prepareForShowPhotoSegue:(UIStoryboardSegue *)segue withIndexPath:(NSIndexPath *)indexPath {
PhotoDisplayViewController *viewController = segue.destinationViewController;
Photo* photo = [self.fetchedResultsController objectAtIndexPath:indexPath];
[viewController setPhoto:[UIImage imageWithContentsOfFile:photo.url]];
}
NSIndexPath is a file structure that is used to represent directory trees. In the context of a table (indexPathForCell:) it contains a section & row index.
Each index in an index path represents the index into an array of
children from one node in the tree to another, deeper, node. For
example, the index path 1.4.3.2 specifies the path shown in Figure 1.
More information in the documentation
NSIndexPath is Mainly used for UITableView Where It will Consider Section as well as Row for That..
so Where ever you want to use NSIndexPath you will be able to access
row and section for that..
so i request you to use indexpath.row for your indexing variable,
if indexpath.section is not useful for you..

Objective-C, Storyboard: instantiateViewControllerWithIdentifier returns nil

I have a UITableViewController with a storyboard push segue linking from the prototype cell to a detail page, a regular old UIViewController. In the storyboard, the detail ViewController has an identifier, and the segue has an identifier which is the same as the detail identifier except that the first letter is lowercase. Furthermore, the detail ViewController has a "custom class" (AttractionDetailViewController) selected in the class pulldown.
Doesn't work. The problem is that instantiateViewControllerWithIdentifier:#"AttractionDetails returns nil.
Relevant code. First the prepareForSegue method which the debugger has never entered.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"attractionDetails"])
{
AttractionDetailViewController *attrDetailVC = [segue destinationViewController];
}
}
Instead it goes into this method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//AttractionDetailViewController *attrDetailVC = [[AttractionDetailViewController alloc] init];
AttractionDetailViewController *attrDetailVC = [self.storyboard instantiateViewControllerWithIdentifier:#"AttractionDetails"];
NSIndexPath *selIndexPath = [self.tableView indexPathForSelectedRow];
attrDetailVC.theAttraction = [attractions objectAtIndex:indexPath.row];
[self.navigationController pushViewController:attrDetailVC animated:YES];
}
Since instantiateViewControllerWithIdentifier returns nil it throws an exception of course. The really interesting thing is, if I use the alloc init line instead, it works, but the screen is all black.
Anyway, I've read up about this and tried a few different things and I'm still stymied. Does anyone have any suggestions?
The problem is that you didn't instantiate your master view controller (the UITableViewController) from the storyboard, so its storyboard property is nil.

How do I use a property in -prepareForSegue?

Here is my code, posted in view1:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([segue.identifier isEqualToString:#"toLevels"])
{
levelViewController *vc = [segue destinationViewController];
vc.currentEnchantmentSelected = self.title;
}
}
This doesn't send the value of "self.title" to the variable in "levelViewController". Why is this? It sends it if I use a string.
Edit (levelViewController):
#synthesize enchantment = _enchantment;
- (enchantmentViewController *)enchantment
{
if (!_enchantment){
_enchantment = [[enchantmentViewController alloc] init];
}
return _enchantment;
}
the #property enchantment is declared in the header.
So from the chat, the issue was that you were setting this property in didSelectRowAtIndexPath:, which is actually called after prepareForSegue:sender: with storyboards. (when the segue is attached to a cell in a table)
So the solution is just to do that work directly in prepareForSegue:sender: instead. The sender will be the cell that was tapped. And if you need the indexPath for that cell you can use:
[self.tableView indexPathForSelectedRow]
Good luck with the app.