2017-07-25 61 views
2

我已经在视图控制器中成功实现了iOS10提供的CNContactPickerViewControllerFacebookUI,因此我可以让用户选择多个联系人来邀请事件。我试图通过实现委托模式来减小这个单一视图控制器的大小,并将其卡在黑屏上。我查看了一些资源,并认为我正在调用委托并相应地定义协议。我有一个视图控制器,CreateEventViewController,它实现了我自定义的ContactsToInviteDelegate。该协议如下:在Swift中重构使用委托模式的CNContactPicker UI代码

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

我ContactPickerViewController自定义的类如下:

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]) { 

    } 

} 

而在CreateEventViewController我打电话委托当我点击邀请用户按钮和实现的方法该协议只是试图打印最终结构显示联系人的电子邮件和电话号码发送邀请:

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

} 

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

此代码无需重构即可尝试使用之前工作的委托模式。我在一个单一的视图控制器中拥有所有这些功能,但是所有这些文件本身所需的逻辑都超出了400多行。我现在的问题是,尝试重构使用委托模式后,当我点击按钮触发selectContactsPicker我所看到的只是一个黑屏。我不知道我做错了什么,但我有一种感觉,就是这个功能本身。我不太清楚这个函数的主体应该是什么,以便将责任委托给正确的控制器,或者如何正确显示它。我看到的示例使用了故事板和赛格,例如this。我研究了其他使用代表的例子,但我认为我的问题有点过于具体,我不知道如何以更一般的方式提问。如果我这样做,我可能不会有这个问题开始,因为那时我可能会正确理解如何实现委托模式。

+0

您正在实例化ContactPickerViewController,但它没有内容,因此您将会看到一个黑屏。您需要以编程方式或从故事板或XIB加载一些内容。在重构代码之前,您是如何定义视图内容的? – Dale

+0

@Dale之前我简单地'let cnPicker = CNContactPickerViewController()'这是ContactsUI的直接。现在我试图使用ContactsUI中的数据来委托代码,但不确定如何或在何处实例化ContactsUI – kinghenry14

回答

1

委托不一定是视图控制器。当视图控制器管理需要委托的元素时,这是一种方便的模式 - 而不是实例化单独的对象,而只是让视图控制器实现协议。

有很多方法可以管理增长过大的不规则视图控制器。

一个简单的方法是使用扩展。要委托协议添加到现有的视图控制器:

extension SomeViewController : CNContactPickerDelegate { 

    ... implement contact picker delegate methods 

} 

这可以很好地compartmentalise你的源代码,使其更容易阅读。

如果你想使用一个单独的类实例作为委托,那也可以很容易地完成。

声明你的委托类,无论是在同一个源文件或其他:

class MyPickerDelegate : NSObject, CNContactPickerDelegate { 

    ... implement contact picker delegate methods 

} 

注意到类必须从NSObject的继承,但并不需要是一个UIViewController。

在你火了联系人选择器的代码:

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

注意选择器视图控制器仅保持一个弱引用的委托,所以你必须确保保持强大的参考对象的某个地方。在这里,我使用属性选择器DeleteDelegate