使用Swift

时间:2017-07-25 03:36:28

标签: ios swift delegates swift-protocols

我已经在iOS10中成功实现了iOS10中提供的CNContactPickerViewController ContactsUI在视图控制器中,因此我可以让用户选择多个联系人来邀请参加活动。我试图通过实现委托模式来减小这个单一视图控制器的大小,并且卡在黑屏上。我查看了一些资源,并认为我正在调用委托并相应地定义协议。我有一个视图控制器CreateEventViewController,它实现了我自己定义的ContactsToInviteDelegate。该协议如下:

protocol ContactsToInviteDelegate : class {
     //array of array of KV-pairs where inner array is {"email":"email@gmail.com", "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当我点击邀请用户按钮并实施协议方法时,我正在呼叫代表,只是尝试打印显示联系人电子邮件和电话号码的最终结构,以发送邀请: / p>

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时,我看到的只是一个黑屏。我不知道自己做错了什么,但我觉得这就是这个功能本身。我不太清楚这个函数的主体应该是什么,以便将责任委派给正确的控制器,或者如何正确显示它。我看到的示例使用了故事板和segues,例如this。我查看了使用代表的其他示例,但我认为我的问题有点过于具体,而且我不知道如何在更广泛的意义上提问。如果我这样做,我可能不会开始这个问题,因为那时我可能会正确理解如何实现委托模式。

1 个答案:

答案 0 :(得分:1)

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

有许多方法可以管理过大的视图控制器。

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

extension SomeViewController : CNContactPickerDelegate {

   ... implement contact picker delegate methods

}

这可以很好地划分您的源代码,使其更易于阅读。

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

在相同的源文件或其他源文件中声明您的委托类:

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)

注意选择器视图控制器仅保留对委托的弱引用,因此您必须确保在某处保留对该对象的强引用。我在这里使用属性pickerDelegate