es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

El módulo debería mostrar una ventana modal/UIViewController en el hilo principal, pero no funciona sin demora.

Estoy intentando presentar UIViewController en mi aplicación React Native desde el módulo de Swift. Lo estoy presentando de esta manera:

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

y obtengo este error:

UIApplication.windows solo debe ser utilizado desde el hilo principal.

Ok, tengo que añadirlo a mi hilo principal:

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

y funciona bien cuando llamo a esta función con un pequeño retraso:

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

o con un retraso en Swift de esta manera:

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

Pero si elimino el retraso, entonces este modal no se muestra. Pero debería estar ahí. Y veo esto en el registro de Swift que confirma mi teoría:

[Presentation] Attempt to present <pkaddpaymentpassviewcontroller: 0x103d6b2e0=""> on <uiviewcontroller: 0x103c25480=""> (from <uiviewcontroller: 0x103c25480="">) which is already presenting <rctmodalhostviewcontroller: 0x10e21df40="">.

PKAddPaymentPassViewController es mi UIViewController.

No sé cómo solucionar este problema…

ACTUALIZACIÓN:

Basado en el primer comentario, hice esto:

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)
    }
}

Y la buena noticia es que el modal aparecerá, pero inmediatamente se cerrará. Veo el efecto de apertura y luego el efecto de cierre…

SOLUCIÓN:
1) todo en la sección de actualización
2) refactorizando el código de RN.
Resultó que hay otra modal abierta antes que la nueva. La modal anterior no se cerró antes de que abra la nueva… así que cierro la antigua más rápido y luego muestro la nueva y todo está bien.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Solución para presentar una UIViewController en una aplicación React Native desde un módulo Swift
    Al presentar una UIViewController en una aplicación React Native desde un módulo Swift, es posible que se encuentre con el error “UIApplication.windows debe ser utilizado solo desde el hilo principal”. Para solucionarlo, puede agregar el código de presentación al hilo principal utilizando el método “DispatchQueue.main.async”.

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

    Sin embargo, esto puede hacer que el modal no se muestre de inmediato. Para solucionarlo, puede agregar un retraso utilizando el método “setTimeout()” o el método “DispatchQueue.main.asyncAfter()”.

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

    Si el modal aún no se muestra, puede que se encuentre con el error “Intento de presentar un UIViewController en otro UIViewController”. Para solucionarlo, puede comprobar si ya hay un controlador de vista presentado y presentar el nuevo encima de él.

    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)
      }
    }
    

    Si el modal se abre y se cierra inmediatamente, puede haber un problema con otro modal ya abierto. Puede intentar cerrar el modal anterior antes de presentar el nuevo para solucionar este problema.

    En general, refactorizar el código de React Native también puede ayudar a evitar estos problemas en el futuro.

Comments are closed.