display new UIview when row is selected from UITableView - ios

I have a UITableView which has 3 rows. the first row calls a phone number when pressed, which is working fine.
I have two other UIViewControllers which I would like to be displayed when the respective row is selected in the UITableView.
Below is my didSelectRow method.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//deselect row
[tableView deselectRowAtIndexPath:indexPath animated:YES];
switch (indexPath.row)
{
case 0:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"tel:1800333000"]];
break;
case 1:
break;
case 2:
break;
default:
break;
}
}
As can be seen, I've set up my switch expression. Im trying to figure out how to call the other two UIViews.
Could someone please provide the code required to display these views?

Your question is not exactly clear about what exactly you are doing but I think what you need is to make a segue and specifically a segue from a UITableViewCell.
First thing to do is control-click and drag a connection from your UITableView cell to the other view in the storyboard. This should create a line between the table view cell and the next view with a little circle. Click on that circle to set and edit the segue properties in the properties inspector. Then in the UITableViewController class you need to have a prepare for segue method. Here is some example code that I've written, its got an extra if statement in there because I actually had 2 UITableViews - one from the UITableViewController and one from the searchbarviewcontroller (which was within the UITableViewController).
// In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([sender isKindOfClass:[UITableViewCell class]]) {
NSIndexPath * SBidxPath = [self.searchDisplayController.searchResultsTableView indexPathForCell:sender];
NSIndexPath * TBidxPath = [self.tableView indexPathForCell:sender];
NSIndexPath * idxPath = [[NSIndexPath alloc] init];
if (!SBidxPath) {
idxPath = TBidxPath;
}
else{
idxPath = SBidxPath;
}
if ([segue.identifier isEqualToString:CELL_PUSH_SEGUE_ID]) {
if ([segue.destinationViewController isKindOfClass:[YTViewController class]]) {
[self prepareYTViewController:segue.destinationViewController withDictionaryEntry:[self.dictionaryEntries objectAtIndex:idxPath.row]];
}
}
}
}
The other thing is that you also need to look into what a NSIndexPath is. Typically the property that you use from that structure is the .row property.

Related

get tableView of a UISearchBar

I have an UISearchBar in on top of my TVC. If the search is active it displays another tableView on top of the normal tableView (this is normal). Now i need to get the "searchTableView" in prepareForSegue() because I need to call:
var newIndexPath = table.indexPathForSelectedRow!
and this fails if you search something.
I also can't do the decision in didSelectRowAtIndexPath() because the segue is called to fast because it is 'linked' directly to the UITableViewCell. I also tried to create the segue from the ViewController but this also fails because the segue needs to end on the same ViewController again.
So basically I want to ask if anyone knows how to solve the error in the Code line above will doing a search.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath;
if (self.searchDisplayController.active)
{
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
}
else
{
indexPath = [self.tableView indexPathForSelectedRow];
}
// Use the indexPath...
}

How to pass the in-place edited content back to the previous tableview controller (update the model)

I have two table views, one called mainTableViewController (mtvc), the other called detailTableViewController (dtvc). It's very typical click the accessory button on the main tableview cell bring you to the detail tableview kinda thing.
In the prepareForSegue method, the data passed from the main tableview to detail tableview is a NSMutableArray called item.
And this is how I got it displayed: cell.detailTextLabel.text = self.item[indexPath.row];
The cool thing is I managed to do in-place editing on the detail table view cell (overwrote the NSTableViewCell, added a UITextField as subview to each cell).
everything works, the last thing I spent whole day cannot figure out is how do I update the NSMutableArray item after in-place editing taken place, the ultimate goal is in-place editing, and the main tableview data shall reflect the change.
I tried to use delegation and protocol but it does not work (the in-place edited content didn't got passed back, part of the reason is I don't know how to capture the edited content, it's not like it's a text field with a name, I can't just do updatedContent = self.myTextField.text to grab the change)
I'm running out of ideas, any help would be highly appreciated, thanks.
Here's the prepareForSegue in the main tableview controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toInventoryDetail"]) {
NSMutableArray *selectedItem = nil;
if (self.searchDisplayController.active) {
selectedItem = _searchResults[[sender row]];
} else {
selectedItem = _appDelegate.items[[sender row]];
}
UPFInventoryDetailTableViewController *idtvc = segue.destinationViewController;
idtvc.item = selectedItem;
}
}
and here's the cellForRowAtIndex at the detail tableview controller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UPFEditableUITableViewCell *cell = [[UPFEditableUITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier];
cell.textLabel.text = _appDelegate.title[indexPath.row];
cell.detailTextLabel.text = self.item[indexPath.row];
[cell showEditingField:YES];
return cell;
}
I wrote the delegation but delete them after cause they didn't work.
I had an idea, still using delegation and protocol obviously: when the 'done' button in the detail tableview hit, I go grab all the row contents and build a new array, using delegation to pass this new array back to the main tableview controller, add this new array into the model meanwhile delete the old one. The tricky thing is still HOW CAN I GRAB ALL THE CONTENTS in the detail tableview?
update:
Haha! I think solved half of the puzzle !
here's the solution for the detail tableview controller
- (IBAction)doneUpdate:(UIBarButtonItem *)sender {
[self.delegate addItem:[self newItem]];
}
- (NSMutableArray *)saveItem
{
NSMutableArray *newItem = [[NSMutableArray alloc] init];
NSArray *indexPathes = [self.tableView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in indexPathes) {
UPFEditableUITableViewCell *cell = (UPFEditableUITableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[newItem addObject:cell.editField.text];
}
return newItem;
}
and here's the main tableview controller
- (void)addItem:(NSArray *)item
{
//take the updated item then insert the items array as new item
[_appDelegate.items addObject:item];
//remove the selected item (the one being updated) from the items array
[_appDelegate.items removeObject:_appDelegate.selectedItem];
[self.tableView reloadData];
[self.navigationController popViewControllerAnimated:YES];
}
When you creating a cell - give tags to your UITextFields
You can collect data entered by its delegate methods - you can either make NSDictionary/ key value pairs or you can add it to NSArray.
- (void)textFieldDidEndEditing:(UITextField *)textField {
if(textField.tag == 11) {
// you can add it to your desired array/dictionary
}
}
OR
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if(textField.tag == 11) {
// you can add it to your desired array/dictionary
}
}
You can use Delegation/Protocol or store this values in NSUserDefault and get it back on mainViewController.
Do you have a separate data model class(classes) for your selectedItem? That would be the appropriate way to persist data between the two TableViewControllers. It can be Core Data or simply a NSMutableArray that lives in memory. The DetailViewController updates the item and saves the changes, then the mainTableViewController reloads the TableView (or even just the data backing the previously edited cell.
Perhaps even consider the Model-View-Controller-Store pattern promoted by BigNerdRanch.

UITableViewCell segues to different static UITableViewController based on row selected?

I have 3 cells in a UITableView. Person, Car and House and I want each one to segue to a custom and different STATIC TableViewController so the user can do some setup.
What is the most efficient way to go about this?
In prepareForSegue do I query and call the method didSelectRowAtIndexPath then do what?
Or in the storyboards do I setup a push segue from one cell to a separate TVC, 3 times?
Does anyone know of any good tutorial? I dont know how to go about this thanks.
I am guessing you are using storyboards? Are the cells static cells, and always in the same order?
If so I am guessing you have a UIViewController or UITableViewController in the storyboard which is populated with Person, Car, and House.
You then have 3 different view controllers that you wish to navigate to depending on which of Person, Car or House is selected?
As you are using prototype cells, I would do the following:
As previously mentioned, when creating the cell do:
[cell setTag:indexPath.row];
then in didSelectRowAtIndexPath do the following:
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
switch ([cell tag]) {
case 0:
PersonDetailViewController *personDetailViewController = [[self storyboard] instantiateViewControllerWithIdentifier:#"PersonDetails"];
[[self navigationController] pushViewController:personDetailViewController animated:YES];
break;
case 1:
// Do similar for Car
breal;
case 2:
// Do similar for House
default:
break;
}
You can do like this:
In your didSelectRowAtIndexPath method, do this:
if(indexPath.row == 1)
{
// push to controller 1
}
else if(indexPath.row == 2)
{
// push to controller 2
}
else if(indexPath.row == 3)
{
// push to controller 3
}
First Connect your main tableview with three individual TVC and add segue for each add identifier for that
then in didSelectRowAtIndexpath check which indexpath has been pressed and call that viewController like below
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.row == 1)
{
[self performSegueWithIdentifier:#"view1" sender:self];
}
else if(indexPath.row == 2)
{
[self performSegueWithIdentifier:#"view2" sender:self];
}
else if(indexPath.row == 3)
{
[self performSegueWithIdentifier:#"view3" sender:self];
}
}
Then in prepareforSegue find which one view is called
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"view1"]){
TableView1 *tableMenu = segue.destinationViewController;
}
else if([[segue identifier] isEqualToString:#"view2"]){
TableView2 *tableMenu2 = segue.destinationViewController;
}
else if([[segue identifier] isEqualToString:#"view3"]){
TableView3 *tableMenu3 = segue.destinationViewController;
}
}
Hope this works if any mistake someone correct me thnx

Setting Specific UITableView rows to push in a specific detail view?

I currently have 7 rows in my UITableView and I'm using segues to push in a detail view. However, I currently have two different view controllers, and want something like this:
If row 1 and 2 are selected push in: "showMenuDetail1"
If row 3 through 4 are selected push in: showMenuDetail2"
This is what I currently have: I'm not sure how to exactly assign rows to a specific one.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showMenuDetail1"]) {
NSIndexPath *indexPath = [self.menuTableView indexPathForSelectedRow];
HomeDetailViewController *HDViewController = segue.destinationViewController;
HDViewController.theName = [[menu objectAtIndex:indexPath.row] name];
}
}
Any help would be appreciated! I know it's an if and else statement but I'm not sure how to write out the exact condition. Thanks!
Create two segues. The important idea is to not attach either to the table view cells, instead drag them both from the view controller containing the table to their respective destinations. Give them each an identifier.
Then in tableView:didSelectRowAtIndexPath:, examine the indexPath.row and trigger the appropriate segue.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row < 2) { // or whatever
[self performSegueWithIdentifier:#"SegueForRows0and1" sender:self];
}
// etc...
}
You can still implement prepareForSegue if you need it, including, if you need it, referring to the tableView's indexPathForSelectedRow.

How to segue from a UISearchBarDisplayController result to a detailViewController

So, using storyboard you can create a segue from the UITableViewCell from the first tableViewController to a detailViewController.
Not too complicated, however, when a UISearchBarDisplayController is introduced into the storyboard mix, how can you segue the results cell to the detailViewController?
I am able to search without a problem, I followed this tutorial: http://clingingtoideas.blogspot.com/2010/02/uitableview-how-to-part-2-search.html
All I can do is select a row from the search, it turns blue and doesn't go to the detailViewController.
I have implemented the method prepareForSegue, which works for the non searched cells, but can't figure out this one.
Here's the solution that's based on the comment by #James Chen. Also using a different IndexPath depending on which state the table is in.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"toDetail"]) {
Person *person = nil;
if (self.searchDisplayController.active == YES) {
NSIndexPath *indexPath = indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
NSLog(#"segue - section: %d, row: %d", indexPath.section, indexPath.row);
person = [self.filteredPersonArray objectAtIndex:indexPath.row];
}
else {
NSIndexPath *indexPath = indexPath = [self.tableView indexPathForSelectedRow];
NSLog(#"segue - section: %d, row: %d", indexPath.section, indexPath.row);
person = [self.personArray objectAtIndex:indexPath.row];
}
[[segue destinationViewController] setPerson:person];
}
}
I tried your solution and found that prepareForSegue is called twice
due to the life cycle and didSelect... -> performSegueWithIdentifier.
self:prepareForSegue: object on destination controller is set
(with wrong index) because
dest:viewDidLoad: the destination controller view is loaded after which
self:didSelectRow...: the index is known and properly set.
self:prepareForSegue: object is now correct but has no side effect.
I then focused on didSelect... and came up with this solution where I deleted the segue and pushed the view programmatically:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DestTableViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"DestViewController"];
CustomObj *custObj = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
custObj = [filteredListContent objectAtIndex:indexPath.row];
} else {
storeToDetail = [self.fetchedResultsController objectAtIndexPath:indexPath];
}
controller.custObj = custObj;
[self.navigationController setNavigationBarHidden:NO];
[self.navigationController pushViewController:controller animated:YES];
// presentViewController::animated:completion is always full screen (see problem below)
}
I then experienced some problems going back because I follow a segue
from a mapView, which lead to:
//DestinationViewController
- (IBAction)back:(id)sender
{
[self.navigationController popToRootViewControllerAnimated:YES]; // list
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; // map
}
which is not the way to do it but for now it works.
However, the first part is easy and clean, and maybe it works for you too?!
Ok I think I got it, it seems like a bit of a hack but it works for my purposes:
I am using storyboard:
I have a UITableview controller with UISearchBarDisplayController directly on top of it. No code just drag and drop.
From there, I followed this tutorial to get the search bar to search correctly http://clingingtoideas.blogspot.com/2010/02/uitableview-how-to-part-2-search.html
However prepareForSegue: would only let me display a cell from the original array, not with the search array.
So I used didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (savedSearchTerm) {
searchRowSelected = indexPath.row; //<-- the trick that worked
[self performSegueWithIdentifier:#"ShowDetail" sender:self];
}
}
searchRowSelected is an int variable that I declared at the top of the class.
didSelectRowAtIndexPath: knew which row I was selecting, but prepareForSegue didn't. Thats why I needed that variable.
This is how I used it in prepareForSegue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"ShowDetail"]) {
dvc = [segue destinationViewController];
NSIndexPath* path = [self.tableView indexPathForSelectedRow];
int row = [path row];
if (savedSearchTerm){ //set the detailViewController with the searched data cell
myDataClass* c = [searchResults objectAtIndex:searchRowSelected];
dvc.myDataClass = c;
}else{ //set the detailViewController with the original data cell
myDataClass* c = [array objectAtIndex:row];
dvc.myDataClass = c;
}
}
}
Also use this code to clean up savedSearchTerm
-(void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller{
[self setSavedSearchTerm:nil];
}
If anyone has a better solution I'm all ears :)

Resources