Time to set a property to pass it to another viewController - ios

I have tableViewController class and want to pass a property to another view controller.
I declared my property,
#property (strong, nonatomic) NSIndexPath *selection;
In protocol tableView:didSelectRowAtIndexPath:, I want to set my selection value into indexPath selected.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// change your selection property
[self setSelection:indexPath];
}
I want to pass that selection into destination view controller by prepareForSegue:sender:
if ([segue.identifier isEqualToString:#"updateItem"]) {
UINavigationController *navController = (UINavigationController *)[segue destinationViewController];
UpdateViewController *viewController = (UpdateViewController *)[navController topViewController];
[viewController setManagedObjectContext:self.managedObjectContext];
NSManagedObject *record = [self.fetchResultsController objectAtIndexPath:self.selection];
if (self.selection) {
[viewController setRecord:record];
}
// reset selection
[self setSelection:nil];
}
My problem is, I NSlog-ing that property on destination view controller and for the first time it showed as null. Secondly, it showed as it set for the first, and so on and so on. It showed what I set before.
So did I miss the concept of setting a property before it goes into another view controller destination? Please let me know this. Any help would be appreciated. Thank you so much.

I finally found the answer. I messed up with how to trigger segue. prepareForSegue runs first before didSelectRowAtIndexPath.
Refer to this we should use either of prepareForSegue or didSelectRowAtIndexPath. So I decide to set my selection in prepareForSegue by get its indexPathForSelectedRow.
[self setSelection:[[self tableView] indexPathForSelectedRow]

Related

Pushing Data from UITableViewCell to ViewController

I am trying to push data from a UITableViewCell into another view controller. I have tried two separate ways, instantiateViewControllerWithIdentifier and also PrepareForSegue. In both instances the ViewController loads correctly but the data is not being passed across (either null, or the first array value).
Here is my instantiateViewControllerWithIdentifier method, when I log the variable within my ViewController it just returns null.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *testNumber = [jobNumberArray objectAtIndex:indexPath.row];
NSLog(#"Job is... %#",testNumber);
StandardInfoViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"StandardInfoViewController"];
controller.JobNr = [jobNumberArray objectAtIndex:indexPath.row];
[self.navigationController pushViewController:controller animated:YES];
}
Prepare For Segue
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"Details" sender: self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"Details"]){
StandardInfoViewController *controller = (StandardInfoViewController *)segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
controller.jobNumber = [jobNumberArray objectAtIndex:indexPath.row];
}
}
When I use the prepareForSegue call I get the first row of my Array, which I understand because it doesn't know the cell, but I don't know how to identify the Cell within the prepareForSegue call.
I hope this makes sense, and any help or pointers would be greatly appreciated.
Thanks
If you drag the segue FROM the tableView-cell in the storyboard, you will then get the cell itself as parameter sender.
then you can use tableView indexPathForCell:sender to get the actual index of the selected cell. Then just fetch your object normally.
I.e. you will not need to implement didSelectRowAtIndexPath
If you still want to use didSelectRowAtIndexPath, just pass the cell as the sender parameter manually. I.e:
[self performSegueWithIdentifier:#"Details"
sender:[self.tableView cellForRowAtIndexPath:indexPath]]
Although your first version with instansiateViewController should work, judging by your code.
Another pattern is to subclass the cells themselves, and let them have a property that is the object that they want to display. Then you can just fetch the object directly from the cell without calling the data-array itself.
Is this what you want?
This is how you identify Cell in prepareForSegue method.
**UITableViewCell *cell=[myTable cellForRowAtIndexPath:path];**
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"Details"]){
StandardInfoViewController *controller = (StandardInfoViewController *)segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
**UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];**
controller.jobNumber = [jobNumberArray objectAtIndex:indexPath.row];
}
}

How to pass data back from multiple view controllers to root view controller using delegate? Ios 7

My storyboard controllers: http://i.stack.imgur.com/4LBEd.png
MenuViewController -> ChooseViewControler -> MapViewController and EditViewController.
I need to pass variable called address from MapViewController or EditViewController to MenuViewController. How i can implement this?
I try to use delegate, from this answer Passing Data between View Controllers
but dont understand, how to tell MapViewController or EditViewController that MenuController is its delegate before we push its on nav stack.
I do this at EditVC and its worked:
- (IBAction)OkButton:(id)sender {
NSString *address = addressInput.text;
MenuTableViewController *menuVC =
[self.navigationController.viewControllers objectAtIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
UITableViewCell *cell = [prevVC.tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = address;
[self.navigationController popToViewController:menuVC animated:YES];
}
I guess you have the classes of these viewcontrollers as
MenuViewController.h,
MenuViewController.m
ChooseViewControler.h,
ChooseViewControler.m
MapViewController.h,
MapViewController.m
EditViewController.h,
EditViewController.m
There is this method called -PrepareForSegue called when you perform a segue either programatically(performSegue method) or by using push or model in navigation controller
implement this on your source ViewController (VC) ie, if you are passing from MapViewController to EditViewController ,
Implement this in the .m file of MapViewController.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"toEditViewController"])
{
EditViewController *destinationVC=(EditViewController*)segue.destinationViewController;
destinationVC.address=self.address;
}
}
Note that you have to identify the segue which is called by its name give in the storyboard
There many be many more segues you need to prepare...you need to do all this in the same method.
identify the segue by name>prepare the methods

Proper way of adding a Segue on a TableView Cell

I have an application where the user selects a certain row in a TableView, and the contents of that Row will be sent to the next ViewController.
So far, I have connected the TableView Cell/Row to the next ViewController via a Segue. The issue I am facing right now is passing the value of the selected row to the next ViewController. I have written code for the didSelectRowAtIndexPath and the prepareForSegue functions.
Here are the functions (In ViewController.m file, the one with the TableView):
The didSelectRowAtIndexPath function:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelectRowAtIndexPath entered");
//itemNameList is a mutable array where I get my TableView data from
NSMutableString *itemName = [itemNameList objectAtIndex:indexPath.row];
//selectedItem is a global mutable string I use to store the selected item to.
selectedItem = itemName;
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected"
message:itemName
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
// Display Alert Message
[messageAlert show];
}
The prepareForSegue function:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"prepareForSegue entered");
if ([[segue identifier] isEqualToString:#"Details"])
{
//DetailViewController is the next ViewController once the user
//selects an item
DetailViewController *detailViewController = [segue destinationViewController];
//the first selectedItem is a property of the second ViewController
//the next selectedItem is the global mutable string
detailViewController.selectedItem = selectedItem;
}
}
The problem is that the prepareForSegue function executes first before the didSelectRowAtIndexPath function. This is a huge issue because that means I don't actually get to pass the value to the second ViewController since the second ViewController has loaded into the screen already.
Does anyone know how to deal with this?
My idea was to somehow get the Row the user selected in the prepareForSegue method but I don't know how to do that either.
Yes, you are right. The prepareForSegue seems to execute before didSelectRowAtIndexPath. So you would need to get selected row in prepareForSegue.
Use the method:
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]
Inside prepareForSegue to get selected row.
Remove the connection you made in the IB between the UItableViewCell and the ViewControllerB and add a segue between ViewControllera to ViewControllerB.
Add:
[self performSegueWithIdentifier:#"nextVC" sender:nil];
at the end of didSelectRowAtIndexPath.
That way prepareForSegue will be triggered after didSelectRowAtIndexPath finished processing.
In prepare for segue
if ([segue.identifier isEqualToString:#"YourIdentifier"]) {
TheNextViewController *tnvc = segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
//then do whatever you have to do
//eg. set property in thenextviewcontroller by tnvc.propertyname = self..

Pass tableviewcell data with segue?

I have a popover segue that goes to a view controller. I want to set some properties in the view controller when a cell is clicked. I tried using -prepareForSegue:, but then I realized that it doesn't have the scope of the selected cell. I know that I have to use:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
delegate method, but I'm not sure how that will affect the popover segue. Do I have to programatically create the popover, or is there another way?
Thanks much!
~Carpetfizz
Use self.tableView.indexPathForSelectedRow to get the data from your table's data source, e.g., the array backing the table data. If, for some reason, you don't want to get the data from your data source, then the sender is the UITableViewCell that was tapped to trigger the segue.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"YourSegueID"]) {
YourDestinationViewControllerClass* destinationController = segue.destinationViewController;
destinationController.somePublicProperty = self.yourTablesDataSourceArray[self.tableView.indexPathForSelectedRow.row];
UITableViewCell *cell = (UITableViewCell *)sender;
destinationController.someOtherPublicProperty = cell.textLabel.text;
}
}
So add an NSIndexPath propriety to your VC. Let's call it selectedCell. In your tableView:didSelectRowAtIndexPath method, save the selected index path to the instance variable.
Then in your prepareForSegue method, use the instance variable.
Alternately, in your prepareForSegue method, you could ask the table view for the currently selected row using the table view's indexPathForSelectedRow method.
The best approach is to use the indexPathForSelectedRow property.
For example you can write a code like this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"YourSegueIdentifier"])
{
NSIndexPath *indexPath = [sender indexPathForSelectedRow];
NextViewController *vc = (NextViewController *)segue.destinationViewController;
vc.yourProperty = #"Some Value";
}
}
Assuming NextViewController as your segue destination controller and yourProperty as the property you want to set during the segue, you can access and set information from your parent controller because indexPathForSelectedRow automatically knows which cell has been clicked.
More information can be found here.

tableview to detailviewcontroller storyboard issue

Here's my problem. I have data being passed into the 'second view controller' by mySQL which currently works great. But when I select on any of the from (UITableView) cells, I am currently not able to open a new view to show the data.
I believe the code issue is with
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
detailedViewController *productinfo = [self.storyboard instantiateViewControllerWithIdentifier:#"productDetails"];
//Retrieve current user array
foodProducts *currentProduct = [bakeryProductArray objectAtIndex:indexPath.row];
productinfo.productName = currentProduct.productName;
productinfo.productImage = currentProduct.productImgUrl;
productinfo.productDescription = currentProduct.productDescription;
[self.navigationController pushViewController:productinfo animated:YES];
}
There have been others who have over came this using nibs but not storyboard.
Can someone point out where I have gone wrong or something I have fundamentally missed?
(I have another project which fully working with navigation controller only. Though this is the 1st project which I have tried to use with the tab bar navigation).
The best way to handle this with a storyboard is to create a segue to the detail view from your mainViewController. This can be from your actual cell or from the controller. In your prepare for segue method, pass the object to the detail view. This uses a fetchedResultsController but the idea is the same. Get the selected cell and pass the object to the detail view.
Here is a sample of how you could pass it while using a segue from the cell itself. Create a segue from the tableViewCell in IB for "selection". Drag that segue to your detailViewController and set the identifier to ShowDetailView then add the following prepareForSegue method.
Make sure to have a property (foodProduct) on your detailViewController that will hold the reference to your selected object. That's what you will pass from your mainViewController.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowDetailView"])
{
DetailViewController *detailViewController = [segue destinationViewController];
foodProducts *currentProduct = [bakeryProductArray objectAtIndex:[self.tableView indexPathForSelectedRow]];
detailViewController.foodProduct = currentProduct;
}
}
try this .....
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Decriptionview *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"Decription"];//#"Decription" is Storybord Id of UiViewController of Decriptionview
detail.wndecDecription=[SortedDecription1 objectAtIndex:indexPath.row];
detail.wndectitle=[SorttedTitle1 objectAtIndex:indexPath.row];
detail.wndeclink=[SortedLink1 objectAtIndex:indexPath.row];
detail.wndecdate=[SorttedDate1 objectAtIndex:indexPath.row];
detail.imgeurl=[sorttedMainImage1 objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detail animated:YES];
}

Resources