ios9 cncontact

ios9 - CNContactViewController forUnknownContact inutilizable, destruye la interfaz



(7)

¿Estás interesado en una solución de API muy privada?

@implementation CNContactViewController (Debug) + (void)load { Method m1 = class_getInstanceMethod([CNContactViewController class], NSSelectorFromString(@"".underscore.s.h.o.u.l.d.B.e.O.u.t.O.f.P.r.o.c.e.s.s)); Method m2 = class_getInstanceMethod([CNContactViewController class], @selector(checkStatus)); method_exchangeImplementations(m1, m2); } - (BOOL)checkStatus { //Leo: Fix bug where in-process contact view controller crashes if there is no access to local contacts. BOOL result; if([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized) { result = NO; } else { result = YES; } return result; } @end

Esta es una solución "mágica" que revierte el uso de Apple de los controladores con errores XPC. Resuelve muchos problemas tanto en los controladores CN modernos como en los controladores AB heredados, que usan los CN internamente.

[Parece estar arreglado en iOS 10!] Entonces, lo que sigue se aplica solo a iOS 9 ...

He estado experimentando con el nuevo marco de contactos de Apple, y he encontrado un gran error en una de las tres formas de CNContactViewController. Destruye la interfaz circundante para que su aplicación se vuelva inútil; El usuario está atascado.

Para que este error sea fácil de ver, publiqué un proyecto de ejemplo en https://github.com/mattneub/CNContactViewControllerBug .

Para experimentar, ejecute el proyecto y siga los siguientes pasos:

  1. Toque el botón (Persona desconocida).

  2. Conceder acceso si se solicita.

  3. Se le muestra el contacto parcial, en nuestra interfaz de navegación (observe el botón Atrás en la parte superior).

  4. Toque Agregar a contacto existente. Aparece el selector de contactos.

  5. Toca Cancelar. En realidad no importa lo que hagas desde aquí, pero tocar Cancelar es más simple y es la forma más rápida de llegar al error.

  6. Ahora estamos de vuelta en el contacto parcial, pero la interfaz de navegación se ha ido. El usuario no tiene forma de escapar de esta interfaz. La aplicación está manguera.

Solo para aclarar, aquí hay capturas de pantalla de los pasos que debe seguir:

Toque Agregar al contacto existente para ver esto:

Toque Cancelar para ver esto; observe que es lo mismo que la primera captura de pantalla, pero la barra de navegación desapareció :

He intentado muchas formas de evitar este error, pero parece que no hay manera. Por lo que puedo decir, esta ventana está siendo presentada por el marco "fuera de proceso" y no es parte de su aplicación. No puedes deshacerte de él.

Entonces, ¿cuál es la pregunta? Supongo que es esto: ¿alguien puede mostrarme una manera de hacer que este controlador de vista (en esta forma) sea utilizable? ¿Hay alguna solución que no haya encontrado?

EDITAR Este error apareció en iOS 9.0 y todavía está presente en iOS 9.1. En un comentario, @SergeySkopus informa que cambiar al marco obsoleto de la libreta de direcciones no ayuda; El error está en la estructura subyacente en alguna parte.


Bueno, encontré tres formas de resolver el problema TEMPORALMENTE.

Versión Swift 2.2:


Opción 1: Agite el dispositivo para mostrar la barra de navegación o descartar directamente

class CustomContactViewController: CNContactViewController { override func viewDidLoad() { super.viewDidLoad() UIApplication.sharedApplication().applicationSupportsShakeToEdit = true } override func canBecomeFirstResponder() -> Bool { return true } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) becomeFirstResponder() } override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) resignFirstResponder() UIApplication.sharedApplication().applicationSupportsShakeToEdit = false } override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) { navigationController?.setNavigationBarHidden(false, animated: true) // or just dismiss // dismissViewControllerAnimated(true, completion: nil) // or pop // navigationController?.popViewControllerAnimated(true) } }


Opción 2: configure un temporizador para forzar que se muestre la barra de navegación. Pero ... también crea un nuevo problema, no puedes editar o compartir el avatar de contacto.

class CustomContactViewController: CNContactViewController { var timer: NSTimer? override func viewDidLoad() { super.viewDidLoad() timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(showNavigationBar), userInfo: nil, repeats: true) } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) timer?.fire() } override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) timer?.invalidate() } @objc private func showNavigationBar() { navigationController?.setNavigationBarHidden(false, animated: true) } }


Opción 3: crear un botón de descartar en la vista superior.

class CustomContactViewController: CNContactViewController { override func viewDidLoad() { super.viewDidLoad() configureDismissButton() } private func configureDismissButton() { guard let topView = UIApplication.topMostViewController?.view else { return } let button = UIButton() button.setImage(UIImage(named: "close"), forState: .Normal) button.addTarget(self, action: #selector(dismissViewController), forControlEvents: .TouchUpInside) topView.addSubview(button) // just use SnapKit to set AutoLayout button.snp_makeConstraints { (make) in make.width.height.equalTo(36) make.bottom.equalTo(8) make.left.equalTo(-8) } } @objc private func dismissViewController() { dismissViewControllerAnimated(true, completion: nil) } var topMostViewController: UIViewController? { var topController = UIApplication.sharedApplication().keyWindow?.rootViewController while topController?.presentedViewController != nil { topController = topController?.presentedViewController } return topController } }


Este es uno de esos problemas que me alegró ver que no estaba solo.

Tengo el mismo problema al mostrar un contacto usando CNContactViewController (contacto :).

Cuando se tocaba la imagen o "compartir contacto", la barra de navegación en la raíz CNContactViewController desaparecería haciendo que el usuario se atascara. Esto no se ha solucionado a partir de iOS 9.3.3.

La solución para mí en este momento es usar la barra de herramientas. El problema es que esto aparece en la parte inferior todo el tiempo, incluso con los datos de imagen para el contacto en pantalla completa.

// initialise new contact view controller to display with contact let contactVC = CNContactViewController(forContact: contact!) // set view controller delegate contactVC.delegate = self // set view controller contact store contactVC.contactStore = self.store // enable actions contactVC.allowsActions = true // disable editing contactVC.allowsEditing = false // add cancel button let cancelButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Cancel, target: self, action: #selector(dismissContactVC(_:))) // add flexible space let flexibleSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil) // add to toolbar contactVC.setToolbarItems([flexibleSpace, cancelButton, flexibleSpace], animated: false) // contact view controller must be embedded in navigation controller // initialise navigation controller with contact view controller as root let navigationVC = SubClassNavigationController(rootViewController: contactVC) // show toolbar navigationVC.setToolbarHidden(false, animated: false) // set navigation presentation style navigationVC.modalPresentationStyle = UIModalPresentationStyle.CurrentContext // present view controller self.presentViewController(navigationVC, animated: true, completion: nil)

Después de esto, aparece una barra de navegación en blanco cuando presenta por primera vez el cncontactviewcontroller para eliminar este subclases uinavigationcontroller, y en viewWillAppear (animado :) Llamo a la función setnavigationbar (oculto: animado :) para ocultar la barra de navegación.

Espero que Apple solucione esto pronto ya que esta es una solución menos que ideal.


Este problema puede resolverse fácilmente. La subclase CNContactViewController y en el método viewDidAppear primero llaman a la superclase y luego inmediatamente configuran leftBarButtonItem con un método de acción que llama a despedir ViewController. También asegúrese de incrustar ese viewController en un controlador de navegación.


Evidentemente, este es un error, ya que Apple finalmente respondió a mi informe de error declarándolo un duplicado.


He ocultado el método UINavigationController para mostrar u ocultar la barra de navegación usando categorías:

@interface UINavigationController (contacts) @end @implementation UINavigationController (contacts) - (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated { NSLog(@"Hide: %d", hidden); } @end

De esta manera, CNContactViewController no puede hacer que la barra de navegación desaparezca. Al establecer un punto de interrupción en NSLog descubrí que este método es llamado por el privado [CNContactViewController isPresentingFullscreen:] .

Al verificar si el self.topViewController del controlador de navegación es de clase CNContactViewController , puede decidir si oculta o no la barra de navegación.


La única forma que encontré para hacer "CNContactViewController forUnknownContact" utilizable es abandonar la barra de navegación y usar una barra de herramientas para salir de la vista modal como esta (en el Objetivo C):

CNContactViewController *picker = [CNContactViewController viewControllerForUnknownContact: newContact]; picker.delegate = self; UINavigationController *newNavigationController = [[UINavigationController alloc] initWithRootViewController:picker]; UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStyleDone target:self action:@selector(YourDismissFunction)]; UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; [picker setToolbarItems:[[NSArray alloc] initWithObjects:flexibleSpace, doneButton, flexibleSpace, nil] animated:NO]; newNavigationController.toolbarHidden = NO; picker.edgesForExtendedLayout = UIRectEdgeNone; [self presentViewController:newNavigationController animated:YES completion:nil];

esperando que pueda ayudar