Search code examples
iosswiftreact-nativereact-native-modules

Modul should show modal/UIViewController in main thread but it doesnt work without delay


I trying to present UIViewController in my React native app from Swift module I am presenting it like this

  let screen = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
  screen?.rootViewController?.present(payController!, animated: true, completion: nil);
  

and I get this error: UIApplication.windows must be used from main thread only

ok I have to add it to my thread

  DispatchQueue.main.async {
    let screen = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
    screen?.rootViewController?.present(payController!, animated: true, completion: nil);
  }

and it works fine when I call this function with small delay

setTimeout(() => {
  showMyWiew();
}, 500);

or delay into swift like this

  DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    let screen = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
    screen?.rootViewController?.present(payController!, animated: true, completion: nil);
  }

but if I remove the delay then this modal is not shown. But it should be there. and i see this in log in swift which confirms my theory:

[Presentation] Attempt to present <PKAddPaymentPassViewController: 0x103d6b2e0> on <UIViewController: 0x103c25480> (from <UIViewController: 0x103c25480>) which is already presenting <RCTModalHostViewController: 0x10e21df40>.

PKAddPaymentPassViewController is my UIViewController

I don't know how to fix this issue...

UPDATE

Based on first comment I did this

  DispatchQueue.main.async {
    let screen = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
    let controller = screen?.rootViewController?.presentedViewController;
    if controller == nil {
      screen?.rootViewController?.present(payController!, animated: true, completion: nil);
    } else {
      screen?.rootViewController?.presentedViewController?.present(payController!, animated: true, completion: nil)
    }

  }

and the good news is the modal will show up but immediately is close I see the open effect and then close effect ...

SOLUTION

  1. all in the update section
  2. refactoring RN code It turned out There is open another modal before this new. The old modal is not closed before I open the new one ... so I close the old modal faster and then I show new and all is good

Solution

  • That is because at that exact moment screen?.rootViewController seems to already present another ViewController (RCTModalHostViewController). A VC that is already presenting some VC can not present yet another VC. What you could do is to call present on the VC that is being presented by the rootViewController at that moment: screen?.rootViewController.presentedViewController?.present(...). (Presenting on a presented ViewController does work. Presenting on a VC that presents another VC does not.)

    If you do that you should also make sure that presentedViewController is actually set and not nil. If it is nil you can just call present on rootViewController as you did earlier.