I had similar problem and my "modal segue chain" was not limited. I agree with the arguments in the answer and comments below about modal segues designed for different thing, but I liked the "horizontal flip" animation of modal segues and I couldn't find the easier way to replicate them... Also in general I don't see anything wrong in using things that were designed for one thing to achieve some other thing, like chaining modal controllers. Repeated "partial curl" animation can also apply to some scenario in some app.
So I implemented the stack of modal controllers as a property of controller:
@interface ModalViewController : UIViewController
@property (nonatomic, retain) NSMutableArray *modalControllers;
@end
When the first modal segue is executed the stack is created in prepareForSegue method of controller that is not modal:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"modalSegue"]) {
ModalViewController *controller =
(ModalViewController *)[segue destinationViewController];
controller.modalControllers = [NSMutableArray arrayWithObject: controller];
}
}
When one modal controller moves to another the destination is added to the stack (in the method of ModalViewCotroller)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"modalSegue"]) {
ModalViewController *destController =
(ModalViewController *)[segue destinationViewController];
// add destination controller to stack
destController.modalControllers = _modalControllers;
[destController.modalControllers addObject: destController];
}
}
To dismiss the whole stack at once was the most tricky part - you can't dismiss the previous controller before the next finished dismissing, so the cycle did not work, only recursive blocks did the trick, with avoiding the memory leak being the trickiest (I'm yet to check it, but I relied on this):
- (IBAction)dismissAllModalControllers: (id)sender
{
// recursive block that dismisses one auth controller
// all these dances are to avoid leaks with ARC
typedef void (^voidBlockType)();
__block void (^dismissController) ();
voidBlockType __weak dismissCopy = ^void(void) {
dismissController();
};
dismissController = ^void(void) {
int count = [_modalControllers count];
if (count > 0) {
// get last controller
UIViewController *controller =
(UIViewController *)[_modalControllers lastObject];
// remove last controller
[_modalControllers removeLastObject];
// dismiss last controller
[controller
// the first controller in chain is dismissed with animation
dismissViewControllerAnimated: count == 1 ? YES : NO
// on completion call the block that calls this block recursively
completion: dismissCopy];
}
};
// this call dismisses all modal controllers
dismissController();
}