2015-10-06 6 views
25

[Erscheint 10 in iOS fixiert zu werden!] Also, was auf iOS 9 gilt folgt nur ...CNContactViewController forUnknownContact unbrauchbar, zerstört Schnittstelle


Ich habe mit Apples neuen Kontakten Rahmen zu experimentieren, und Ich habe einen großen Fehler in einer der drei Formen von CNContactViewController gefunden. Es zerstört das umgebende Interface, so dass deine App nutzlos wird; Der Benutzer ist festgefahren.

Um diesen Fehler einfach zu sehen, habe ich ein Beispielprojekt unter https://github.com/mattneub/CNContactViewControllerBug veröffentlicht.

zu experimentieren, das Projekt ausführen und die folgenden Schritte ausführen:

  1. die Schaltfläche Tippen (Unbekannt Person).

  2. Zugriff gewähren, wenn angefordert.

  3. Sie sehen den Teilkontakt in unserer Navigationsoberfläche (beachten Sie die Zurück-Schaltfläche oben).

  4. Tippen Sie auf Zu bestehendem Kontakt hinzufügen. Die Kontaktauswahl erscheint.

  5. Tippen Sie auf Abbrechen. Es spielt eigentlich keine Rolle, was Sie von hier aus tun, aber Tippen auf Abbrechen ist am einfachsten und ist der schnellste Weg, um den Fehler zu erreichen.

  6. Wir sind jetzt wieder am Teilkontakt, aber die Navigationsschnittstelle ist weg. Der Benutzer hat keine Möglichkeit, von dieser Schnittstelle zu entkommen. Die App ist abgespritzt.

Nur um zu klären, hier sind Screenshots der Schritte, die Sie brauchen:

enter image description here

Tap Zu Kontakt hinzufügen, das zu sehen:

enter image description here

Tippen Sie auf Abbrechen, um dies zu sehen. zu beobachten, dass es der gleiche wie der erste Screenshot ist, wird aber die Navigationsleiste gegangen:

enter image description here

ich viele Möglichkeiten versucht haben, um diesen Fehler zu arbeiten, aber es scheint keine Möglichkeit zu geben. Soweit ich das beurteilen kann, wird dieses Fenster vom Framework "out-of-process" dargestellt und ist nicht Teil Ihrer App. Du kannst es nicht loswerden.

Also, was ist die Frage? Ich denke, es ist das: kann mir jemand einen Weg zeigen, diesen View-Controller (in dieser Form) nutzbar zu machen? Gibt es einen Workaround, den ich nicht gefunden habe?

BEARBEITEN Dieser Fehler erschien in iOS 9.0 und ist immer noch in iOS 9.1 vorhanden. In einem Kommentar berichtet @SergeySkopus, dass die Umstellung auf das veraltete Adressbuch-Framework nicht hilfreich ist. Der Fehler ist irgendwo in der zugrunde liegenden Struktur.

+0

Diese Tests wurden mit iOS 9 und (auf dem Gerät) iOS 9.0.2 durchgeführt. Als Radar 22984883 an Apple gemeldet. – matt

+0

Wenn Sie einen Workaround finden, bitte aktualisieren Sie diesen Beitrag. Habe ähnliche Probleme. Es ist noch schlimmer auf dem iPad, wo, wenn Sie [CNContactViewController viewControllerForContact:] verwenden und dann versuchen, einen Geburtstag zu bearbeiten, das gleiche passiert ... die Navigationsleiste verschwindet vollständig und der Benutzer bleibt auf diesem Bildschirm stecken. Es sieht auch nicht so aus, als ob das Problem in iOS9.1 (Beta3) behoben wurde. –

+0

@ZS Ich nehme an, Sie haben Fehler eingereicht? – matt

Antwort

6

Offensichtlich ist dies ein Fehler, da Apple endlich auf meinen Fehlerbericht geantwortet hat, indem er es als Duplikat deklariert hat.

+2

@mattt können Sie bitte den Link für diesen gemeldeten Fehler teilen – jay

+0

Hier ist eine, die ich auf [Open Radar] (https://openradar.appspot.com/23971668) gefunden habe. Ich habe das gleiche Problem mit UIPopoverPresentationController auf dem iPhone (auf dem iPad ist es perfekt) ... – Shebuka

8

Ich habe die UINavigationController Methode für die Show versteckt oder die Navigationsleiste ausblenden, indem Sie Kategorien mit:

@interface UINavigationController (contacts) 
@end 

@implementation UINavigationController (contacts) 

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

Auf diese Weise der CNContactViewController kann nicht die Navigationsleiste machen zu verschwinden. Einen Haltepunkt auf NSLog festlegen Ich entdeckte, dass diese Methode von dem privaten [CNContactViewController isPresentingFullscreen:] aufgerufen wird.

Durch die Überprüfung, ob die self.topViewController des Navigationscontrollers Art der Klasse CNContactViewController ist, können Sie entscheiden, ob die Navigationsleiste ausgeblendet wird oder nicht.

+1

Extrem schlau! Das Problem ist, dass die Navigationsleiste nicht mehr verschwindet, wenn Sie die Liste der Kontakte aufrufen (z. B. tippen Sie auf Vorhandene Kontakte hinzufügen). Das ist falsch. Aber Sie haben sicherlich gezeigt, wo das Problem liegt: Die Liste der Kontakte sollte vor allem angezeigt werden, aber sie erscheint nur vor der Kind-Ansicht des Navigations-Controllers. Das muss der Grund sein, warum sie stattdessen die Navigationsleiste verstecken. – matt

+0

Leider hat die Lösung, wie sie hier gepostet wird, Nebenwirkungen, wie zum Beispiel das Halten der Sendetaste in 'MFMailComposeViewController'. Ich nehme an, Methode swizzling könnte verwendet werden, um die ursprüngliche 'setNavigationBarHidden: animated:' Methode aufrufen zu können. – newenglander

4

Der einzige Weg, ich fand „CNContactViewController forUnknownContact“ nutzbar zu machen, ist die navigationbar zu verlassen und eine Symbolleiste wie diese modale Ansicht verlassen verwenden (in Objective 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]; 

die Hoffnung, dass es

helfen könnte
+0

Sehr schlau, und es gibt dem Benutzer einen Weg aus der Benutzeroberfläche - die Navigationsleiste ist zerstört, aber die Symbolleiste ist nicht, so dass die Schaltfläche Fertig vorhanden und funktionsfähig bleibt. Leider gibt uns das auch eine leere Navigationsleiste. Auch wenn Sie die Navigationsleiste zunächst ausblenden, erscheint sie erneut, wenn Sie Neuen Kontakt erstellen und anschließend auf Abbrechen klicken. Ich denke, dass ich die andere Problemumgehung besser deshalb mag. – matt

+0

Sehr hilfreich, ich habe gerade 'initWithBarButtonSystemItem: target: action:' anstelle von 'initWithTitle: style: target: action:' verwendet, um zu vermeiden, ein anderes Wort übersetzen zu müssen. – newenglander

-1

Dieses Problem kann leicht gelöst werden. Unterklasse CNContactViewController und in der ViewDidAppear-Methode rufen Sie zuerst die Superklasse auf und legen dann unmittelbar danach leftBarButtonItem mit einer Aktionsmethode fest, die den Befehl "disneyViewController" aufruft. Stellen Sie außerdem sicher, dass Sie diesen viewController in einen Navigationscontroller einbetten.

2

Sind Sie an einem sehr privaten API-Fix interessiert?

Dies ist eine "magische" Lösung, die Apples Verwendung der fehlerhaften XPC-Controller zurücknimmt. Löst so viele Probleme sowohl in den modernen CN-Controllern, als auch in den Legacy AB-Controllern, die intern die CN-Controller verwenden.

+0

Welcher Selektor für die Methode m1? –

+0

@AshutoshDave Lesen Sie es aus der Antwort. –

0

Nun, ich habe drei Wege gefunden, um das Problem VORÜBERGEHEND zu lösen.

Swift 2.2 Version:


Option 1: Schütteln Gerät Navigationsleiste angezeigt oder direkt

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) 

    } 
} 


Option 2 entlassen: Stellen Sie einen Timer die Navigationsleiste zu zwingen, zu zeigen. Aber ... es erzeugt auch ein neues Problem, Sie können den Kontaktavatar nicht bearbeiten oder teilen.

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


Option 3: Erstellen Sie eine Taste auf der obersten Ansicht entlassen.

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

enter image description here

0

Dies ist eines der Probleme ist, ich war froh, dass ich nicht allein zu sehen war.

Ich habe das gleiche Problem beim Anzeigen eines Kontakts mit CNContactViewController (Kontakt :).

Wenn das Bild oder 'Kontakt teilen' angetippt wurde, verschwand die Navigationsleiste im Stammverzeichnis CNContactViewController und der Benutzer blieb stecken. Dies wurde ab iOS 9.3.3 nicht behoben.

Die Lösung für mich zu diesem Zeitpunkt ist die Verwendung der uitoolbar. Das Problem ist, dass dies immer unten erscheint, auch bei den Bilddaten für den Kontakt im Vollbildmodus.

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

Danach eine leere Navigationsleiste angezeigt wird, wenn Sie zuerst die cncontactviewcontroller präsentieren, so diese entfernen ich subclassed UINavigationController und in viewWillAppear (animiertes :) ich die Funktion setnavigationbar (versteckt nennen: animiert :) die Navigation verstecken Bar.

Ich hoffe, dass Apple dies bald behebt, da dies eine weniger als ideale Lösung ist.