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
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.