Reputation: 31
I have a UITableViewController that has a cell which drills down to another UITableViewController displaying a large dataset. To improve usability I have added a UISearchController to the view. When the search is completed the user should click the cell which, using an unwind segue, returns the user to originating view controller bringing back its data. There is an embedded navigator as well to assist with navigation.
If I don't perform a search and simply click the cell it correctly unwinds and populates the selection in the originating cell, but if I do a search and then select a cell I get the following error:
popToViewController:transition: called on while an existing transition or presentation is occurring; the navigation stack will not be updated.
Here is my initialization code of the UISearchController:
override func viewDidLoad() {
super.viewDidLoad()
// Initialise search controller settings
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
searchController.dimsBackgroundDuringPresentation = false
searchController.delegate = self
searchController.searchBar.delegate = self
tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
}
Is there a trick to achieving this functionality?
Thanks.
Upvotes: 3
Views: 565
Reputation: 45
I had the same issue and there is my solution and explainations: When searchController.isActive = true, it pushes viewController (which contains searchController) at navigationController by itself. So, attempting to unwind from viewController to initialViewController, gives an error you described. To avoid this problem you must firstly dismiss searchController. So, instead using this line
performSegue(withIdentifier: "unwindSegueFromViewControllerToInitialViewController", sender: self)
you must use this block:
if searchController.isActive {
searchController.dismiss(animated: false, completion: {
self.performSegue(withIdentifier: "unwindSegueFromViewControllerToInitialViewController", sender: self)
})
} else {
performSegue(withIdentifier: "unwindSegueFromViewControllerToInitialViewController", sender: self)
}
Upvotes: 0
Reputation: 720
I got same errors from searchResultTableView in iOS 9.0 later. I call unwind segue trigger in searchResultTableView but it doesn't move to the destinationVC even though I have a success to deliver its data to the destinationVC.
I solve this issue with creating custom unwind segue.
Let's take a look at the app structure and its logic. The structure would be looks like this:
CustomNavigationController(subclass of UINavigationController) -> MainVC -> push segue -> SearchVC(subclass of UISearchController)
If you select the cell from the searchResultTableView,
an app is move to MainVC using unwind segue. I think that you are already set unwind segue in the storyboard. So, you can just set data to deliver to the destionationVC and call performSegueWithIdentifier
method in this method.
// SearchVC or SearchResultVC
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
CustomData *customData = self.searchResults[[self.tableView indexPathForSelectedRow].row];
self.selectedData = customData;
[self performSegueWithIdentifier:@"PassResult" sender:nil];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Implement prepareForSegue:sender method in SearchVC or SearchResultVC for passing data to the destinationVC(MainVC)
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:@"PassResult"]) {
MainVC *destVC = (MainViewController *)segue.destinationViewController;
destVC.selectedData = self.selectedData;
}
}
Move to rootVC in your navgiation controller when you call unwind segue with performSegueWithIdentifier method. You are two options to do that. Use unwind segue method or create custom segue.
unwind segue method
If you connect searchWithResult
method(in MainVC) for unwind segue id PassResult
:
- (IBAction)searchWithResult:(UIStoryboardSegue *)segue
{
[self.navigationController popToRootViewControllerAnimated:YES];
// Add your code to process your custom data from unwind segue
....
}
custom segue
Create custom segue and implement -perform
method. You can add your custom animation. I just want to move to RootVC in here.
@implementation CustomUnwindSegue
- (void)perform
{
UIViewController *sourceViewController = (UIViewController *)self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *)self.destinationViewController;
[destinationViewController.navigationController popToRootViewControllerAnimated:YES];
}
@end
implement segueForUnwindingToViewController:fromViewController:identifier method in CustomNavigationController. This method could not be called depend on push or modal state, but it works in this app structure.
// refer to : http://hmcreation.net/?p=279
-(UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController
fromViewController:(UIViewController *)fromViewController
identifier:(NSString *)identifier{
UIStoryboardSegue *segue;
if ([identifier isEqualToString:@"PassResult"]) {
segue = [[CustomUnwindSegue alloc]
initWithIdentifier:identifier
source:fromViewController
destination:toViewController];
}else{
if ([super respondsToSelector:@selector(unwindForSegue:towardsViewController:)]) {
NSLog(@"unwinding in iOS9 later");
[super unwindForSegue:segue towardsViewController:toViewController];
}
NSLog(@"segueForUnwinding in iOS9 below");
segue = [super segueForUnwindingToViewController:toViewController
fromViewController:fromViewController
identifier:identifier];
}
return segue;
}
In iOS9 later, you can override unwindForSegue:towardsViewController method in your custom navigationController. The document of this method describe that it can dealt with pop up viewControllers to move to the destination. But it looks like that it doesn't work in UISearchController.
Upvotes: 0