Micheal
Micheal

Reputation: 305

iOS 13 Dismiss Modal Page Sheet with a button

So I need some help with dismissing a page sheet modal screen in iOS 13. I have looked at several posts and none helped.

iOS 13 Modals - Calling swipe dismissal programmatically

Looking at the 2nd answer I tried that but I kept getting that self was implicit and needed to be explicit. Tried researching that but didn't find to much.

All I want to do is have a Done button in the upper right of nav bar. When that button is pushed I need for it to connect to the database and save the data if it is valid (already implemented). Then it needs to dismiss the modal screen and refresh the table so that it gets the newest changes.

I have read up on delegates but didn't help much. I read a bit up on UIAdaptivePresentationControllerDelegate and I understand the basics behind it and being able to pull to close the modal. But not sure how to duplicate that in the button. I did remember reading to set the presentation delegate. Or something to that effect.

let navigationController = segue.destination as! UINavigationController
let editSensorVC = navigationController.topViewController as! EditSensorViewController

navigationController.presentationController?.delegate = editSensorVC

It was saying this was how I set the Delegate, but not sure where to go from here.

Upvotes: 1

Views: 3698

Answers (2)

flanker
flanker

Reputation: 4210

If the originating VC is of type PresentingVC, and the modal of type PresentedVC, I'd use the below approach. Given the segue statement above I assume you're using storyboards, but if not replace the prepare(for segue:) with injecting the delegate value when you instantiate yourPresentedVC

For starters, set your PresentedVC up to hold a delegate by defining the delegate protocol and providing a delegate property.


protocol PresentedVCDelegate {
   func presentedVCDidUpdateDatabase()
}

class PresentedVC {
    var delegate: PresentedVCDelegate?

    @IBAction buttontapped(_ sender: Any) {
        //existing code to validate and save data to databse
        delegate?. presentedVCDidUpdateDatabase()
        dismiss(animated: true)
    }
}

Update the PresentingVC so that it injects itself as the delegate when instantiating its child VC:

class PresentingVC {

    //all the current code

    // and amend preapre(for:) something like
    func prepare(for segue: UIStoryboardSegue, sender: Any?) {
      // Get the new view controller.
       if let presented = segue.destination as? PresentedVC {
          presented.delegate = self
          //anything else you do already
       }
    }
}

The extend it to support the protocol method

extension PresentingVC: PresentedVCDelegate {
    func presentedVCDidUpdateDatabase() {
        tableView.reloadData()
        //any other work necessary after PresentedVC exits
    }
}

Note: written from memory and not compiled, so may contain minor typos, but hopefully it's enough detail to get the concept across?

Upvotes: 2

Larry Pickles
Larry Pickles

Reputation: 4646

here, this is how you do it objective-c in the presenting viewcontroller that really isn't presenting anything but it's navigationcontroller is. this is the easy mode.

UIViewController *pvc = [UIViewController new];
WLGNavigationController *nav = [[WLGNavigationController alloc] initWithRootViewController:pvc];
UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(backerPressed)];
[[pvc navigationItem] setLeftBarButtonItem:backBarButtonItem];
[[self navigationController] presentViewController:nav animated:true completion:nil];

with backer pressed being this:

- (void)backerPressed {
  [[self navigationController] dismissViewControllerAnimated:true completion:nil];
}

for the hard hard modes:

completion handler:

add a completion handler to the VC you're presenting, then in the VC you presented, you add the navigation button then add an action that when pressed, you run that completion handler after the promise is executed as finished. then in the presenting view controller, you set up the completion handling code to then dismiss the presented navigation/view controller combo.

Delegation:

write a delegate in the VC you're presenting, when the promise returns, execute the delegate methods, "responds to selector" blah blah, like you'd normally do with delegation. in the presenting VC you then make it the delegate of the VC you're presenting, implement the method that when called calls for the navigation controller to dismiss it's presented navigation/viewcontroller package.

Upvotes: 0

Related Questions