I have a problem with using SWRevealViewController. How to call prepare for segue in didSelectRowAtIndexPath? It is necessary because in tableView I have name of categories and some of this categories have its own subcategories. For example my list:
- category1
- category2
+ category3
- category4
So, when I click on + category3 I should see
- category1
- category2
+ category3
- subcategory1
- subcategory2
- category4
But I could not to do this because of prepareForSegue
Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section <= _categories.count) {
GDCategory *category = [[_subCategories objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
_gdCategory = category;
if (category.subcategories.count > 0) {
NSNumber *categoryId = #(category.dbId);
if ([_selectedSubCategories containsObject:categoryId]) {
[_selectedSubCategories removeObject:categoryId];
} else {
[_selectedSubCategories addObject:categoryId];
}
NSLog(#"There are %lu subcategories in %#", (unsigned long)category.subcategories.count, category.name);
[self recalcSubcategories];
[tableView reloadData];
} else {
//Here I should call prepareForSegue
}
NSLog(#"selected category is %#", category.name);
}
}
- (void)prepareForSegue: (UIStoryboardSegue *)segue sender:(id)sender {
// configure the destination view controller:
if ( [sender isKindOfClass:[UITableViewCell class]] ) {
UINavigationController *navController = segue.destinationViewController;
GDCategoryVC *categoryVC = [navController childViewControllers].firstObject;
if ( [categoryVC isKindOfClass:[GDCategoryVC class]] ) {
categoryVC.selectedCategory = _gdCategory;
}
}
}
Also, I could not to pass data throw VCs, because prepareForSegue call firstly. Please help me. Thanks!
//in prepareForSegue method
NSIndexPath *indexPath = [tableView indexPathForSelectedRow];
and you can get selected row value by using indexPath.row
To change the current View you shouldn't call prepareForSegue. Use performSegueWithIdentifier instead. PrepareForSegue will be called automatically.
If you want to pass the UITableViewCell as sender you need to call the cellForRowAtIndexPath from your TableViewDataSource
else {
//Here I should call prepareForSegue
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath] //call self if dataSource is implement in your class
[self performSegueWithIdentifier:segueIdentifier sender:cell] // Insert your identifier for the wished Segue
}
With SWRevealController it can happen that the View did changed like it should, but the RevealMenu is still visible. For that issue you can call:
[self.revealViewController setFrontViewPosition:FrontViewPositionLeft animated:YES];
Related
Here is what I go so far:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (preivousViewController isEqualToString:#"...")
{
if ([self.filteredArray count] == 0)
self.person = self.users[indexPath.row];
else
self.person = self.filteredArray[indexPath.row];
self.mugshot = cell.imageView.image;
[self performSegueWithIdentifier:#"SelectPerson" sender:self];
} else {
if ([self.filteredArray count] == 0)
self.person = self.users[indexPath.row];
else
self.person = self.filteredArray[indexPath.row];
self.mugshot = cell.imageView.image;
[self performSegueWithIdentifier:#"selectVisitee" sender:self];
}
}
It looks messy, that's why im trying to fix it up (that previousViewController part is just made up to show you what I want to try to do).
What im trying to say is: If how you got to this view was via this segue, or from that view controller with the name suchandsuch, then preform this segue or that segue. Is there a way I can do that?
You can check the previous ViewController of the stack from the Navigation Controller.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([self.filteredArray count] == 0)
self.person = self.users[indexPath.row];
else
self.person = self.filteredArray[indexPath.row];
self.mugshot = cell.imageView.image;
//Not the viewcontroller name string. Use the ViewController class name
if ([self backViewController] == YOURVIEWCONTROLLER)
{
[self performSegueWithIdentifier:#"SelectPerson" sender:self];
} else {
[self performSegueWithIdentifier:#"selectVisitee" sender:self];
}
}
Use this below method,
- (UIViewController *)backViewController
{
NSInteger numberOfViewControllers = self.navigationController.viewControllers.count;
if (numberOfViewControllers < 2)
return nil;
else
return [self.navigationController.viewControllers objectAtIndex:numberOfViewControllers - 2];
}
I have a UITableView which when you select a row, it will lead you into the "details" of the selected row. However, the first time I click the row, it goes into the prepareForSegue method, without calling didSelectRowAtIndexPath. When I push the back button on the detail view, the app goes back, and if I select the row again, the method will be called.
I'm NOT using the didDeselectRowAtIndexPath.
This patter will continue and I can't figure out why. When I load my data, I do call [tableview reloadData].
I have also tried to add self.TagsTableView.allowsMultipleSelection = YES; to my viewDidLoad method.
Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
self.bluetoothManager = [[BlueToothLEManager alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reloadTableView:) name:#"ScanComplete" object:nil];
self.Tags = self.bluetoothManager.Tags;
NSLog(#"Fetch Tags: %#", self.Tags);
}
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [fetchTagsTableView dequeueReusableCellWithIdentifier:#"tagCell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"tagCell"];
}
FetchTag* newTag = [fetchTags objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%# %d", newTag.tagName, indexPath.row];
cell.detailTextLabel.text = [newTag.tagUUID UUIDString];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedTagFromTable = [fetchTags objectAtIndex:indexPath.row];
[TagsTableView deselectRowAtIndexPath:indexPath animated:YES];
}
...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
if([[segue identifier] isEqualToString:#"DetailView"]){
TagDetailViewController* ftdvc = [segue destinationViewController];
[ftdvc setSelectedTag:selectedTagFromTable];
}
// Pass the selected object to the new view controller.
}
-(void)reloadTableView:(NSNotification*)notif{
NSLog(#"Reloading Table View");
NSLog(#"Fetch Tags: %#", self.Tags);
[self.TagsTableView reloadData];
}
I would have put the code from the didSelectRowAtIndexPath: to the prepareForSegue: instead Try using the sender parameter to identify a selected tag
I have a tableview controller and I would like to override the segue for the final row. Instead of going to the standard destination view controller I want to send it to another controller. How do I do this?
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *myIndexPath = [self.tableView
indexPathForSelectedRow];
long row = [myIndexPath row];
if ([[segue identifier] isEqualToString:#"ShowLocationsTableView"])
{
LocationsTableViewController *ViewController =
[segue destinationViewController];
ViewController.categoryDetailModel = #[_categoryTitle[row],
_categoryImages[row]];
}
}
This is the current prepareForSegue and I would like to change it. I would like to send it to another view controller using a segue "aboutCat". How do I do this?
I don't understand what happens between prepareForSegue [current] and viewDidLoad [destination]. Thanks
Sideeffects
Initial problem was solved by 'Nikita Took' yet there are some side effects
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
long row = [myIndexPath row];
if ([_categoryTitle[row] isEqualToString:#"About"])
{
NSLog(#"SKIPPING PREPARE");
}
else if ([[segue identifier] isEqualToString:#"ShowLocationsTableView"])
{
LocationsTableViewController *ViewController =
[segue destinationViewController];
ViewController.categoryDetailModel = #[_categoryTitle[row],
_categoryImages[row]];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == self.tableView)
{
// I assume you have 1 section
NSLog(#"DIDSELECTROW");
NSLog(#"INDEX PATH %i", indexPath.row + 1);
NSLog(#"%i", [tableView numberOfRowsInSection:0]);
if (indexPath.row + 1 == [tableView numberOfRowsInSection:0])
{
NSLog(#"ABOUT");
[self performSegueWithIdentifier:#"aboutCat" sender:self];
}
else
{
NSLog(#"ELSE");
[self performSegueWithIdentifier:#"ShowLocationsTableView" sender:self];
}
}
}
Now the about works!!! But if I click on another row which is one of the mainSegue. It will call the subview controller 2x. I can verify this with NSLOG statements in the detailview viewdidload. The issue is that now the navigation controller takes two steps to return home.
[home] -> [detail view] -> [same detail view]
I can verify that the didselectrowatindexpath happens before the prepareforsegue
Any ideas why two segues are preformed?
Assume you have two segues: MainSegue (for all rows except the last one) and LastRowSegue (for the last row) you can do:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == self.tableView) {
// I assume you have 1 section
if (indexPath.row == [tableView numberOfRowsInSection:0]) {
[self performSegueWithIdentifier:#"LastRowSegue" sender:self];
} else {
[self performSegueWithIdentifier:#"MainSegue" sender:indexPath];
}
}
}
Try this for prepareForSegue. If it's not what you need, please explain what do you mean
It works but I'm getting double layered table views
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"MainSegue"]) {
NSIndexPath *selectedIndexPath = sender;
LocationsTableViewController *locationController = segue.destinationViewController;
locationController..=categoryDetailModel = #[_categoryTitle[selectedIndexPath.row], _categoryImages[selectedIndexPath.row]];
}
}
You can't do this in prepareForSegue -- the source and destination view controllers are already defined by the time prepareForSegue is called. You need to make two segues from your controller (not the cell) and call performSegueWithIdentifier:sender" in didSelectRowAtIndexPath. Choose which segue to perform based on the indexPath.
You can do something like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int lastIndex=[tableArray count]-1;
if (indexPath.row == lastIndex) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
NSString* viewType = #"MenuVC";//u can have the identifier of the LocationViewCOntroller or where ever you wanna go from here
UIViewController* viewController = [storyboard instantiateViewControllerWithIdentifier:viewType];
self.navigationController.viewControllers = [NSArray arrayWithObjects:viewController, nil];
} else {
[self performSegueWithIdentifier:#"usualSegue" sender:self];
}
}
So what I am trying to do is I have an NSMutableArray of data I need to pass to another UITableViewController. This NSMutableArray is an array of NSDictionaries that contain the information I want to be displayed in the title of each table view cell. Here is my code before I segue.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath* indexPath = [self.tableView indexPathForCell:sender];
if ([segue.identifier isEqualToString:#"Title Query"]) {
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
NSString* cellText = cell.textLabel.text;
NSMutableArray* photosToBeShown = [self titleQuery:cellText];
if ([segue.destinationViewController respondsToSelector:#selector(setPhotoTitles:)]) {
[segue.destinationViewController performSelector:#selector(setPhotoTitles:) withObject: photosToBeShown];
NSLog(#"%#", photosToBeShown);
}
}
}
The method setPhotoTitles: that is called by the performSelector: withObject: is the setter of the property (NSMutableArray* ) photoTitles on the UITableViewController that I am seguing to because I wanted to collect the array so I could then call the methods below to set the titles of my table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Photo Title Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [self titleForRow:indexPath.row];
return cell;
}
- (NSString *) titleForRow: (NSUInteger) row
{
return self.photoTitles[row];
}
What happens when I run this code is I end up in an infinite loop with calls to my setter method (setPhotoTitles:). Now my question is what is the right conceptual way to get around this problem or how can I implement it this way without ending up in an infinite loop. I have all the information I need in my array but I need to pass the array to the new controller but also be able to use the UITableViewCell method to set the rows titles.
In the prepareForSegue: method, rather than overriding setPhotoTitles:, you should create a NSArray property in the destination view controller, as pass the photoTitles array to the NSArray property of the destination view controller. So your prepareForSegue method would look like this:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath* indexPath = [self.tableView indexPathForCell:sender];
if ([segue.identifier isEqualToString:#"Title Query"]) {
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
NSString* cellText = cell.textLabel.text;
NSMutableArray* photosToBeShown = [self titleQuery:cellText];
YourCustomViewController *customViewController = segue.destinationViewController;
customViewController.photosArrayProperty = photosToBeShown;
}
}
I'm implementing the search bar for my project. The search part is ok. I can display the raw data and filter the data with the search text. When I tap on the cell of the search result tableView, it didn't transition to the detail view. But for the raw data I can transition to the detail view. I use the prepareForSegue method as I'm using storyboard.
Here's the code so far,
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString: #"Book Detail Segue"]) {
BookDetailsTVC *bookDetailsTVC = segue.destinationViewController; // for the detail view controller
bookDetailsTVC.delegate = self;
if (self.tableView == self.searchDisplayController.searchResultsTableView) { // The if block is not working
NSLog(#"Search Display Controller");
bookDetailsTVC.book = [self.searchResults objectAtIndex: self.searchDisplayController.searchResultsTableView.indexPathForSelectedRow.row];
} else {
NSLog(#"Default Display Controller");
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
bookDetailsTVC.book = [self.objects objectAtIndex: indexPath.row];
}
}
}
When I tried using didSelectRowAtIndexPath method, I can transition to the detail view. But I got error message like that:
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
Unbalanced calls to begin/end appearance transitions for <BookDetailsTVC: 0x69b5300>.
Here's the code for didSelectRowAtIndexPath:
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath
{
BookDetailsTVC *bookDetailsTVC = [[BookDetailsTVC alloc] init];
if (tableView == self.searchDisplayController.searchResultsTableView) {
bookDetailsTVC.book = [self.searchResults objectAtIndex: self.searchDisplayController.searchResultsTableView.indexPathForSelectedRow.row];
[self performSegueWithIdentifier: #"Book Detail Segue" sender:self];
NSLog(#"Search Display Controller");
} else {
bookDetailsTVC.book = [self.objects objectAtIndex: indexPath.row];
[self performSegueWithIdentifier: #"Book Detail Segue" sender: self];
NSLog(#"Default Display Controller");
}
}
Thanks for help.
The problem is solved,
Change this in cellForRowAtIndexPath
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
to
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier: CellIdentifier];
and in the prepareForSegue method, you can use the self.searchDisplayController.active to check the current tableview
if (self.searchDisplayController.active) {
NSLog(#"Search Display Controller");
bookDetailsTVC.book = [self.searchResults objectAtIndex: self.searchDisplayController.searchResultsTableView.indexPathForSelectedRow.row];
} else {
NSLog(#"Default Display Controller");
bookDetailsTVC.book = [self.objects objectAtIndex: self.tableView.indexPathForSelectedRow.row];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
self.selectedPerson = [self.searchResults objectAtIndex:indexPath.row];
PersonasDetalle *pd = [self.storyboard instantiateViewControllerWithIdentifier:#"PersonaDetalle"];
pd.persona = self.selectedPerson;
[self.navigationController pushViewController:pd animated:YES];
}
}