2017-07-25 5 views
2

J'ai implémenté le CNContactPickerViewController ContactsUI fourni par iOS dans iOS10 avec succès dans un contrôleur de vue afin que je puisse avoir un utilisateur sélectionner plusieurs contacts pour inviter à un événement. J'essaye de réduire la taille de ce contrôleur de vue simple en mettant en application le modèle de délégué, et suis collé sur un écran noir. J'ai regardé quelques ressources, et pense que j'appelle le délégué et que je définis le protocole en conséquence. J'ai un contrôleur de vue, CreateEventViewController et il implémente mon auto-défini ContactsToInviteDelegate. Ce protocole est le suivant:Refactoring CNContactPicker UI Code en utilisant le modèle de délégué dans Swift

protocol ContactsToInviteDelegate : class { 
    //array of array of KV-pairs where inner array is {"email":"[email protected]", "phone": "+18965883371"} 
    //array of JSON objects to upload 
    func contactsToInvite(_ contactsStructure: [[String:String]]) 
} 

Mon auto classe définie ContactPickerViewController est la suivante:

class ContactPickerViewController: UIViewController, CNContactPickerDelegate { 
    //class variables 
    let phoneNumberKit = PhoneNumberKit() 
    weak var delegate: ContactsToInviteDelegate? 
    var contactsToSendInvitesTo = [[String:String]]() 

    func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) { 
     contacts.forEach { contact in 
      let phoneNum = contact.phoneNumbers.first 
      var stringPhoneNumber = String() 
      do{ 
       let phoneNumber = try self.phoneNumberKit.parse((phoneNum?.value.stringValue)!, withRegion: "US", ignoreType:true) 
      stringPhoneNumber = "+1\(phoneNumber.adjustedNationalNumber())" 
      print(stringPhoneNumber) 
      } 
      catch { 
       print("phone number parsing error") 
      } 

      let contactDisplayName = contact.givenName 
      print("displayName: \(contactDisplayName)") 

      let contactEmail = contact.emailAddresses.first?.value ?? "" 
      print("email: \(contactEmail)") 

      self.contactsToSendInvitesTo.append(["email":contactEmail as String, "phone":stringPhoneNumber]) 
     } 
     delegate?.contactsToUpload(self.contactsToSendInvitesTo) 
    } 

    func contactPickerDidCancel(_ picker: CNContactPickerViewController) { 
     print("cancel contact picker") 
    } 

    func contactPicker(_ picker: CNContactPickerViewController,didSelectContactProperties contactProperties: [CNContactProperty]) { 

    } 

} 

Et dans le CreateEventViewController j'appelle le délégué lorsque je clique sur le bouton Inviter des utilisateurs et mettre en œuvre la méthode de le protocole pour tenter juste d'imprimer la structure finale affichant les contacts des courriels et des numéros de téléphone pour envoyer des invitations à:

func selectContactsPicker() { 
     let cnPicker = ContactPickerViewController() 
     cnPicker.delegate = ContactPickerViewController() as? ContactsToInviteDelegate 
     self.present(cnPicker, animated:true, completion:nil) 

} 

func contactsToInvite(_ contactsStructure: [[String : String]]) { 
    print(contactsStructure) 
} 

Ce code sans refactoring pour essayer d'utiliser le modèle de délégué travaillé auparavant. J'avais toutes ces fonctions dans un seul contrôleur de vue, mais avec toute la logique requise, ce fichier s'étend sur plus de 400 lignes. Mon problème maintenant est qu'après avoir essayé de refactoriser en utilisant le modèle de délégué, quand je clique sur le bouton pour déclencher selectContactsPicker tout ce que je vois est un écran noir. Je ne sais pas ce que je fais de mal, mais j'ai le sentiment que c'est cette fonction elle-même. Je ne suis pas tout à fait sûr de ce que le corps de cette fonction devrait être afin de déléguer la responsabilité au contrôleur correct, ou comment l'afficher correctement. Exemples J'ai vu des storyboards et des segues utilisés, tels que this. J'ai regardé d'autres exemples d'utilisation de délégués mais je pense que mon problème est un peu trop spécifique et je ne sais pas comment le demander de façon plus générale. Si je le faisais, je n'aurais probablement pas ce problème pour commencer, car alors je comprendrais probablement comment implémenter le modèle de délégué.

+0

Vous instanciez ContactPickerViewController mais il n'a pas de contenu, donc vous obtiendrez un écran noir. Vous devez charger du contenu par programmation ou à partir d'un storyboard ou XIB. Avant de refactoriser le code, comment avez-vous défini le contenu de la vue? – Dale

+0

@Dale avant de simplement 'laisser cnPicker = CNContactPickerViewController() 'qui est le ContactsUI directement. Maintenant, j'essaie de déléguer le code en utilisant les données de ContactsUI, mais je ne sais pas comment ou où instancier le ContactsUI – kinghenry14

Répondre

1

Un délégué ne doit pas être un contrôleur de vue. C'est un modèle pratique lorsqu'un contrôleur de vue gère les éléments nécessitant des délégués - plutôt que d'instancier des objets séparés, laissez simplement le contrôleur de vue implémenter le protocole.

Il y a un certain nombre de façons de gérer les contrôleurs de vue indisciplinés qui deviennent trop grands.

Une manière simple consiste à utiliser des extensions. Pour ajouter un protocole de délégué à un contrôleur de vue existant:

extension SomeViewController : CNContactPickerDelegate { 

    ... implement contact picker delegate methods 

} 

Cela peut bien compartimenter votre code source qui rend plus facile à lire.

Si vous souhaitez utiliser une instance de classe distincte en tant que délégué, cela peut également se faire assez facilement.

Déclarez votre classe déléguée, que ce soit dans le même fichier source ou d'une autre:

class MyPickerDelegate : NSObject, CNContactPickerDelegate { 

    ... implement contact picker delegate methods 

} 

note la classe doit hériter de NSObject, mais n'a pas besoin d'être un UIViewController.

Dans le code où vous lancez le sélecteur de contact:

picker = CNContactPickerViewController() 
self.pickerDelegate = MyPickerDelegate() 
picker.delegate = self.pickerDelegate 
self.present(picker, animated: true) 

contrôleur de vue du sélecteur de note ne conserve qu'une référence faible au délégué, vous devez vous assurer de garder une forte référence à l'objet quelque part. Ici, j'utilise un sélecteur de propriétésDelegate