Does anyone know how to \"stop\" a segue transition conditionally:
My table view cells represent products which can be viewed in a drill-down \"detail\" view... or
In your - (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender;
method, you could add some code such as:
if ([[segue identifier] isEqualToString:@"DemoSegue"] && !self.canOpenDemo) {
id *nc = [segue destinationViewController]; // UIViewController, UINavigationController, etc. (keeping "id" will return warning)
[nc dismissModalViewControllerAnimated:NO];
}
And this will stop the view from opening, however I have not checked, but it seems like it will have already called your destination view controllers initialize function (again, I haven't checked in Xcode, so I'm not entirely sure).
The way Apple's template does it for the iPad popOver is by using a manual segue, as opposed to a automatic segue that triggers on a touch the manual one needs to be triggered with performSegueWithIdentifier:
To create a manual segue instead of ctrl-dragging from the element you have in mind ctrl-drag from the view's controller icon, set a identifier for the segue and you are done in IB.
I am using an much easier and tidy approach.
Storyboard
Table View
This way looks a lot easier to implement and also does not alter the way segues are supposed to work.
I don't know if it is the right way to do it but I discovered a workaround.
From the storyboard I associate(control+click) a segue from the status bar in the view controller. Give the segue an ID (for example: switchSegue).
Now, from an action in your code (in my code I use a button), I call:
[self performSegueWithIdentifier:@"switchSegue" sender:sender];
That way you can control if your segue is performed or not. Try tutorials that helped me from here and here
Hope this helps.
A nice and lightweight way of doing this is inside the UITableViewDelegate method tableView:willSelectRowAtIndexPath:
—where applicable. YMMV.
Here's how I'm doing it (iOS 5, ARC). I use a BOOL instance variable in my view controller, initially set to False in viewDidLoad
. The destination view controller that the table cells are set to segue to in Interface Builder rely on a bit of data having gotten loaded from a server, so I don't want the segue to happen until I have the data.
Simplified, this is what it looks like:
@implementation SomeViewController {
BOOL okayToSegue;
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
okayToSegue = NO;
// The success block for the data retrieval
void(^successBlock)(void) = ^{
// Other code...
okayToSegue = YES;
}
[[ServerClient sharedClient] getDataFromServerSuccess:successBlock];
}
...
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!okayToSegue) {
return nil;
}
return indexPath;
}
Ignore details like that sharedClient bit there, it's just how I'm calling out to my AFHTTPClient subclass with the success block, in real life I'd have a failure block and other things as well.
Returning nil
in tableView:willSelectRowAtIndexPath:
causes tapping on a table cell to do nothing. Only after I've gotten word from my AFHTTPClient instance (through successBlock) that the data the segued-to view controller needs is ready and waiting, I change the instance variable and future taps will work just fine. In real-life code, you'll want to have some user-visible notification or visually obvious tell-tale sign that segueing is not yet possible.
So whatever logic you need to determine if segueing from a table cell is OK or not is, in many cases, possible to do in this manner.
I may be wrong here, but after struggling myself with this, I just disabled the cell's user interaction on the cells where I didn't want the seque triggered (in cellForRowAtIndexPath:). Seems to work perfectly, and it's only 1 line of code!
cell.userInteractionEnabled = NO;