How to get [tableView indexPathForSelectedRow] From a different View [duplicate] - objective-c

This question already has answers here:
What's the best way to communicate between view controllers?
(4 answers)
Closed 8 years ago.
In my TableViewController.m I can easily get the selected row by doing [tableView indexPathForSelectedRow] but I want to get this value from DIFFERENT view. So when my TableViewController goes to my DetailViewController. I want my DetailViewController to have the data of the selected cell.

In a proper architecture, a Controller is designed so that it acts as a black box to other Controllers. In your example, it's not a very good practice that the Details controller searches for the TableViewController's selected item. Instead your TableViewController should use the DetailViewController as a 'service' and somehow pass the selected object as an argument, or set it as a property of the 'service provider' (DetailController).
For example
// this is still the TavleViewController's code
id selectedObject = // ... get selected object somehow... indexPathForSelectedRow or whatever
DetailViewController *newView = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[newView showDetails:selectedObject];
Here, the function showDetails is just an example, it's a function you implement to pass the seleted object as argument.
EDIT:
How you do it depends on your model. Supose each object in your model represents a person. Your MainTableView has a list of names and the detailView shows the details about the selected Person. In such a case, which is typcial, you would have a class that represents Person, and the list of persons would be somewhere in an array. So...
NSIndexPath *i = [tableView indexPathForSelectedRow];
Person *selectedPerson = [self.myArrayOfPersons objectAtIndex:i.row];
// here you instantiate or show the details view
[detailsView showDetails:selectedPerson]; // this is one option, you could also use a property
// for example
detailsView.selectedPerson = selectedPerson; // this is an alternative to the showDetails,
In the DetailsViewController you could have something like this
- (void)showDetails:(Person *)person
{
// just fill your controls witht the person's information: age, birth place, address...
[self.someTextView setText:person.name]
}

Related

Presenting correct View Controller instance depending on cell selection in UITableView

I understand this might be covered in parts in answers to other questions (see references) I've seen on the site, but due to my limited experience I haven't been able to understand each part as it relates to my code. Please forgive me for any duplications.
I have a PFQueryTableViewController (essentially a UITableViewController) called threadsViewController that sources cell information from a Parse backend. The table view consists of threads similar to what you would see on a web forum.
I then have a separate class postsViewController which is another PFQueryTableViewController that I wish to display a table of all the responses ('posts') to that particular thread.
The functionality I'm looking for is for a user tapping on a thread (left screen in the image) to be presented with a postsViewController (right screen) containing only those posts/responses related to that thread. (See basic diagram below).
What I do know from my research:
The Parse backend is established with classes for Thread and Post.
I'm probably going to use the didSelectRowAtIndexPath delegate method
What I need help with:
How can I know which thread cell a user tapped on, and then pass that on so that the postsViewController only displays posts from that Thread?
A layman's description of how to use indexPath.row etc
I understand how to complete PFQueries etc to get the data for the cells, I just don't know how to implement the navigation and how to tell postsViewController which posts to show.
In case it helps somehow, here is my implementation so far. I have tried addign a property to the postsViewController called fromThread to somehow store the thread but apart from that I'm out of ideas!
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
postsViewController *postsVC = [[postsViewController alloc] init];
postsVC.fromThread = //?
[self performSegueWithIdentifier:#"threadsToPosts" sender:self];
}
References
How to filter a Parse query by an tableview index?
Pass Index Number between UITableView List segue
didSelectRowAtIndexPath and prepareForSegue implementation
You're on the right track. You need know how to do two things: (1) access your parse objects by indexPath, and (2) push a new view controller in a navigation controller.
(1) is simpler: PFQueryTableVC provides a method called objectAtIndexPath: that does just what you need.
// indexPath is the indexPath parameter to the didSelectRow delegate method
PFObject *fromThread = [self objectAtIndexPath:indexPath];
(2) is simple, too. But more complicated because there are a couple ways to do it. Segue is the more modern way, but I think the old way is simpler, and certainly easier to describe in code. View Controllers are given storyboard ids on the "Identity" tab in the storyboard editor. Give your Posts-presenting VC a storyboard id like "PostVC".
To get a new instance, use that storyboard id as follows:
MyPostVC *postVC = [self.storyboard instantiateViewControllerWithIdentifier:#"PostVC"];
// initialize it with the PFObject we got above
postVC.fromThread = fromThread;
// present it on the navigation stack
[self.navigationController pushViewController:postVC animated:YES];
And fromThread is just what the PostVC will need to form a query for posts associated with the selected thread.
You can pass data of cell to next ViewController in prepareForSegue with something like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"threadsToPosts"]) {
UINavigationController *navCon = segue.destinationViewController;
postsViewController *postsViewController = [navCon.viewControllers objectAtIndex:0];
// Whatever you are populating your tableView with
Thread *thread = [self.thread objectAtIndex:self.tableView.indexPathForSelectedRow.row];
postsViewController.thread = thread;
}
}

pass parameter to context menu's selector method [duplicate]

This question already has answers here:
Question about Objective-C selectors; Can I use parameters and how?
(2 answers)
Closed 9 years ago.
how can i pass a parameter to the following selector?
NSMenuItem *item3 = [[NSMenuItem alloc] initWithTitle:title3 action:#selector(uncheckrow:) keyEquivalent:#""];
i would like to pass on the number of the row to the method.
Thanks
EDIT
the row i want to pass is the row of the table i rightclicked in the first place. but it could be any integer variable..
Override the menuForEvent: in your tableview's subclass, Take some variable in your controller say 'rowToApply'
- (NSMenu*) menuForEvent:(NSEvent*)event
{
NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
NSInteger row = [self rowAtPoint:point];
BOOL clickWasOnItem = (row > -1);
if(clickWasOnItem) {
controller.rowToApply = [self itemAtRow:row];// Controller can be datasource(or) delegate (or) someObject which can be accessible)
}
return [super menuForEvent:event];
}
you can use the rowToApply: in contextualMenu item's action method (uncheckrow:).
The menu item itself (item3 your snippet) will be sent to the method, so you can identify the particular selected menu item that way. You can also set the NSMenuItem's tag property, for example: [item3 setTag:3] and then in your uncheckrow method you can use NSInteger row = [sender tag];
Edit: For updated question
If you want to send an arbitrary integer to this method then there are options, but they aren't particularly elegant. AppKit will always send the NSMenuItem as the sender, so you need to make the integer available to the NSMenuItem being unchecked. Note that NSMenuItems have access to their parent NSMenus, through the menu method. So if the parent NSMenu itself has some property you can take advantage of, you can use [[sender menu] thatProperty]. Since you're showing the NSMenu in response to a right click on a table's row, you could set the property before you show the menu. I recommend subclassing NSMenu to add your own "spawningRowIndex" property (choose a better name though). Before showing the NSMenu set the property and when you receive uncheckrow you can use [[sender menu] spawningRowIndex].

passing data iOS nsmutable array

I have a tableview and a detailview and I can pass data from my tableview to the detail view by including the detail view.h and setting some values from distance with initWithNib.
DetailView *detailView = [[DetailView alloc] initWithNibName:#"DetailView" bundle:[NSBundle mainBundle]];
//passing data gekozenSpel
detailView.gekozenSpel = [tableData objectAtIndex:indexPath.row];
But now I have a data table with multiple entries and one of then is set, that is: can be changed, in the detailview, from 0 to 1 or from 1 to 0, as a string. It works all fine but now I want to apply the change backwards to the table view and that doesn't work.
myTableView *myTableview = [[myTableView alloc] initWithNibName:#"myTableView" bundle:[NSBundle mainBundle]];
[myTableView.theTable replaceObjectAtIndex:location withObject:value];
For if you use an initWithNib way-of-doing then you create a new empty table nsmutablearray. But I want to CHANGE a value in that array at a specific location with a specific content.
Maybe a singleton to access the data from everywhere? I tried but I have to create instances of what I declare as value and then it is private and not public. So I don't understand how you apply a singleton then.
Any help would be appreciated,
Jan
You will need to add a delegate to the DetailView, this delegate will pass a new array to the old view, this array will have the new tableData that you will replece
For more information on the delegate, here are some tutorials
http://www.roostersoftstudios.com/2011/04/12/simple-delegate-tutorial-for-ios-development/
How to use custom delegates in Objective-C
Simple Delegate Example?
I replace in the detail view the property (eigenschap) of the heart symbol (favourite: YES or NO), then that whole array is put over the mother array (dataVoorMijnTabel) to have it updated back into the main table view (mijnTabelView).
[eigenschappendata2 replaceObjectAtIndex:locatiehartje withObject:eigenschaphartje];
mijnTabelView *mtb = [[mijnTabelView alloc] initWithNibName:#"mijnTabelView" bundle:[NSBundle mainBundle]];
mtb.dataVoorMijnTabel = eigenschappendata2;

Determine the last selected row when returning from detailView of UITableView

Ok I push a detailView when row is selected in the UITableView. In the detailView I set som data and pass that to the webservice. I want to retrieve some data either before the detailView is pushed or when it will disapear. Based on the data retrieved will I set an UIImage as an indicator.
I wonder how I can determine the indexpath.row the detailView got pushed for and use that for setting the UIImage. Is this possible?
I have a UISegmentedControl which loads two different datasources for the UITableView.
For testing I pass the indexpath.row when the detailView is pushed and callback to the UITableView class along with a boolean if the UIImage should be display.
But my problem is that indexpath.row is 0 when the UITableView loads.
And when changing datasource back and forth and passing the indexpath.row with it, the indicator will be display on wrong rows.
The two datasources for the table is:
if (index == 0) {
dictionary = [firstArray objectAtIndex:indexPath.row];
}
else {
dictionary = [secondArray objectAtIndex:indexPath.row];
}
I then set the indicator for that row (will be the UIImage later):
if (indexPath.row == selectedIndex) {
cell.indicator.text = #"Begin";
}
When the detailView is pushed in didSelectRowAtIndexPath i pass in the indexPath.row:
NSInteger rowIndex = indexPath.row;
[self.detailViewController initWithDetailsSelected:rowIndex:dictionary];
When the detailView is done the UITableView class receives the callback:
- (void)processAttendanceSuccessful:(BOOL)successful:(NSInteger)_selectedIndex{
self.selectedIndex = _selectedIndex;
}
So based on a boolean a UIImage should be display for the correct row in the UITableView.
Any suggestions how I can go about this. It must be quite common to set some value in a detailedView and display some data for a specific row in the UITableView, but having a rather hard time finding any good tutorials for this.
I only find how to pass data into the detailView, which I dont have any problem with.
Thanks in advance people.
Don't deselect the row in tableView:didSelectRowAtIndexPath:. When you return to this view controller, just use indexPathForSelectedRow method of the UITableView object.
But in the long run this makes little sense. Since the table view reuses those cells, you also need to remember the rows that have the image. You will probably have to maintain an array for this. In which case, you can either pass the array and the index path to the detail view controller and update them there or use delegate or notification mechanism to update the array from within the table view controller.
I would use an ivar of int, using negative values to represent null selection:
#interface MyController : UIViewController {
int lastSelection;
}
...
#end
#implementation MyController
...
- (void)initWithBlablabla{
...
lastSelection = -1;
}
...
#end
However, I think you should better re-think about your design referring to KVO programming guide. In general MVC patterns, a controller is not the right place to store the state of the model.

Is there a way to change sectioned tableview to drilldown tableview?

I have a sectioned tableview with a plist wich is an array filled with dictionaries.
In my app all sections and cells are shown on the first view.
But now I need to change it to look like this: sections have to become cells(with names of sections). When you press this cell the cells contained in section have appear.
Is there a way to do it without too much rewriting the code?
Thanks and sorry for the noob question :o)
I understand, that you still want to use one tableview, where cells are hidden for all sections except one. In that case you can do this:
Implement -tableView:headerForSection: and place a button on the view that you will return. Write the sections number on the buttons tag. Add an action to the button with parameter (UIButton *)sender: `-(void) headerPressed:(UIButton *)sender
You need to implement -tableView:heightforHeaderInSection: as-well.
-(void) headerPressed:(UIButton *)sender writes the senders tag to a member integer and reloads the tableview.
in -tableview:numberOfRowsInSection: you return 0 if the sections int is not equal to the member integer you saved. If it is equal, return the number of rows in that section.
You will need to create two table view classes. One for the one that holds the section names, and the other that holds the rows of each section. In the first one, retrieve the section names from the plist and populate the rows in the table accordingly. Then in the - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method you need to push another view controller onto the navigation stack(something like this-provided in the template code):
// Navigation logic may go here. Create and push another view controller.
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
Then for the other table view class you populate it by reading in the info from the plist that corresponds to the tapped section. Hope this helps.