简体   繁体   中英

How can a modal view controller be dismissed if the presenting view controller is changed?

I am presenting a modal view controller on the iPad which changes the presenting view controller while presented. For example:

  1. A view controller VC presents the modal view controller when the user selects a cell in a table view.
  2. The user selects an item on the modal view controller and another VC instance is opened in place of the first. Importantly, the view controller instance replacing the first is of the same type.
  3. The modal view controller cannot be dismissed or an EXC_BAD_ACCESS exception occurs.

The failing dismiss is understandable: the presenting view controller is no longer available. Basically, how would I dismiss this presented modal view controller from a different presenting view controller?

The code I already have is:

ViewController1.m

- (void)showModalViewController:(UIViewController *)viewController
{
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
    navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
    viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissModalViewController)];
    [self presentViewController:navigationController animated:YES completion:nil];
}

- (void)dismissModalViewController
{
    [self dismissViewControllerAnimated:YES completion:nil];
    [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}

Thanks for your suggestions but I solved the issue by using delegation. The presented view controller defined a delegate to notify the presenter when an action occurred.

ChildViewControler.h:

@protocol ChildViewControllerDelegate <NSObject>
- (void) childView:(ChildViewController *)childView didSelectItem:(Item *)item;
@end

ChildViewController.m:

// in interface
@property (nonatomic, weak) id <ChildViewControllerDelegate> delegate;

// in implementation
- (void)closeView:(Item *)anItem
{
    [self.delegate childView:self didSelectItem:anItem];
}

ViewController1.m:

- (void)showModalViewController:(UIViewController *)viewController
{
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
    navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
    viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissModalViewController)];
    // Different view controller types may be passed here so check is required...
    if (viewController.class == [ChildViewController class]) {
        ((ChildViewController *)viewController).delegate = self;
    [self presentViewController:navigationController animated:YES completion:nil];
}

- (void)childView:(ChildViewController *)childView didSelectItem:(Item *)item
{
    [self dismissViewControllerAnimated:YES completion:nil];
    [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
    // Perform action required with 'item'
}

You can try to change

self.presentingViewController 

(The view controller that presented this view controller or its farthest ancestor.) property in your modal View Controller before dismissing.

As per document presentingViewController is a readonly property. You could not modify it.

@property(nonatomic,readonly) UIViewController *presentingViewController NS_AVAILABLE_IOS(5_0);

Here is your problem:

 //...
        viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissModalViewController)];
    //...
- (void)dismissModalViewController
{
    [self dismissViewControllerAnimated:YES completion:nil];
    [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}

You try to dismiss presenter view controller (that is currently seems to be swithced to another already) instead of presented modal view controller (in your case it UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; ) so (if presenters view controllers not the tabs of tabViewController or not stored in navigationController's stack or somewhere else) you must to store reference to it somewhere else than in presenter view controller which will be switched and could be deallocated.

I have not tested this code but there may be error in dismissModalViewController.
please put break point on this method the first line is perfect may your second line may cause error,may self.tableView is not accessible or self.tableView indexPathForSelectedRow may be nil.

    - (void)dismissModalViewController
{
    [self dismissViewControllerAnimated:YES completion:nil];    
    [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}

Thanks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM