Presentar un controller de vista sin cambiar el color de la barra de estado, como UIAlertController

Al realizar algunas operaciones de networking, presento un controller de vista modal (similar a MBProgressHUD pero como controller de vista) para evitar la interacción del usuario e indicar el progreso.

El controller de vista tiene modalPresentationStyle = .Custom y se anima utilizando un delegado de transición y un controller de presentación personalizado. Más allá de animar las transiciones, no tienen acciones personalizadas que impulsan la presentación.

El problema que tengo es que cada vez que se presenta el controller de vista, el color de la barra de estado cambia a negro. Podría anular prefernetworkingStatusBarStyle para que siempre devuelva .LightContent pero a veces este controller de vista se presenta sobre un controller de vista con .Default y tampoco quiero cambiarlo allí. Básicamente, quiero tener el mismo comportamiento que UIAlertController .

Captura de pantalla que muestra el controlador de visualización que provoca el contenido oscuro de la barra de estado.

He intentado configurar el controller de presentación para mover el controller de vista presentado fuera del espacio de barra de estado:

 private class SEUIProgressControllerPresentationController: UIPresentationController { override func shouldPresentInFullscreen() -> Bool { return false } private override func frameOfPresentedViewInContainerView() -> CGRect { return super.frameOfPresentedViewInContainerView().insetBy(dx: 40, dy: 100) } ... } 

Estas configuraciones mueven la parte superior del controller presentado fuera de la barra de estado, pero la barra de estado todavía se ve afectada. ¿Hay alguna propiedad que me falte que impida que mi controller de vista actualice el estilo de la barra de estado?

Actualizar

Parece que esto se ha solucionado en iOS 10. El comportamiento pnetworkingeterminado es ignorar las reglas de la barra de estado del controller de vista presentado a less que el controller de vista presentado tenga modalPresentationCapturesStatusBarAppearance == true o utilice uno de varios controlleres de presentación incorporados que se extiendan en el espacio de la barra de estado (no .custom ).

Básicamente, el comportamiento para la personalización ha cambiado a la opción de exclusión pnetworkingeterminada en lugar de opt-in forzada.


Para iOS 9.xo inferior

Después de mucha excavación, la lógica interna para configurar el color de la barra de estado de la aplicación se ve así:

 var viewController = window.rootViewController! while let presentedViewController = viewController.valueForKey("_presentedStatusBarViewController") as? UIViewController { viewController = presentedViewController } while let childViewController = viewController.childViewControllerForStatusBarStyle() { viewController = childViewController } let style = viewController.prefernetworkingStatusBarStyle() 

La propiedad del controller de vista _presentedStatusBarViewController se asigna durante la presentación en function del valor del método privado del controller de presentación _shouldChangeStatusBarViewController() . La implementación pnetworkingeterminada de este método es devolver true, con _UIAlertControllerPresentationController y un puñado de otros controlleres de presentación que devuelven falso.

Eso significa que la forma más directa de no cambiar esa barra de estado es simplemente agregar este método a mi controller de presentación:

 private class SEUIProgressControllerPresentationController: UIPresentationController { @objc func _shouldChangeStatusBarViewController() -> Bool { return false } ... } 

Desafortunadamente, esto no pasará una revisión de App Store.

En cambio, lo que estoy haciendo es recreando la lógica que se aplicaría al controller de vista de presentación en mi controller de vista:

 public class SEUIProgressController: UIViewController { ... public override func prefernetworkingStatusBarStyle() -> UIStatusBarStyle { guard var targetViewController = presentingViewController else { return .LightContent } while let parentViewController = targetViewController.parentViewController { targetViewController = parentViewController } while let childViewController = targetViewController.childViewControllerForStatusBarStyle() { targetViewController = childViewController } return targetViewController.prefernetworkingStatusBarStyle() } public override func prefersStatusBarHidden() -> Bool { guard var targetViewController = presentingViewController else { return false } while let parentViewController = targetViewController.parentViewController { targetViewController = parentViewController } while let childViewController = targetViewController.childViewControllerForStatusBarHidden() { targetViewController = childViewController } return targetViewController.prefersStatusBarHidden() } }