CNContactPickerDelegate的contactPickerDidCancel从未被调用过

当我使用没有与之关联的数字的CNContactPickerViewController选择联系人时,永远不会调用此委托方法。

 /*! * @abstract Invoked when the picker is closed. * @discussion The picker will be dismissed automatically after a contact or property is picked. */ optional public func contactPickerDidCancel(picker: CNContactPickerViewController) 

如果我选择一个有号码的联系人,则会调用它。 但是从方法文档来看,无论如何都应该调用它。

我的问题是,如果用户选择没有号码的联系人,我需要提供一个UIAlertController 。 但是,只有在CNContactPickerViewController才能执行此操作。

我可以通过在viewDidAppear使用一些逻辑来变得非常hacky但似乎应该有一个更清洁的方式。

唯一剩下的委托方法是:

 /*! * @abstract Singular delegate methods. * @discussion These delegate methods will be invoked when the user selects a single contact or property. */ optional public func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) optional public func contactPicker(picker: CNContactPickerViewController, didSelectContactProperty contactProperty: CNContactProperty) /*! * @abstract Plural delegate methods. * @discussion These delegate methods will be invoked when the user is done selecting multiple contacts or properties. * Implementing one of these methods will configure the picker for multi-selection. */ optional public func contactPicker(picker: CNContactPickerViewController, didSelectContacts contacts: [CNContact]) optional public func contactPicker(picker: CNContactPickerViewController, didSelectContactProperties contactProperties: [CNContactProperty]) 

这对于确定CNContactPickerViewController实际离开屏幕没有帮助。

(Xcode8 / swift2.3 / iOS10)

您可以弹出这样的提醒。 您还可以添加一个“再试一次”按钮并重新启动选择器。

  func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) { let name = CNContactFormatter.string(from: contact, style: .fullName) let phones = contact.phoneNumbers if phones.count == 0 { let alertController = UIAlertController(title: "Error", message: "\(name) has no phone numbers", preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "Ok", style: .default) { (action) in }) picker.dismiss(animated: false){ self.present(alertController, animated: true) {} } } //Do stuff here } 

我同意这似乎很奇怪你需要以编程方式解雇选择器,当它自己解散时。 BTW for macOS有你需要的委托方法:

 - (void)contactPickerWillClose:(CNContactPicker *)picker; // In macOS, called when the contact picker's popover is about to close. - (void)contactPickerDidClose:(CNContactPicker *)picker; // In macOS, called when the contact picker's popover has closed. 

无论如何,由于某些原因,这些委托方法不适用于iOS开发人员。 下面是另一种处理这种情况的方法:由于CNContactPickerViewControllerUIViewController类的CNContactPickerViewController程序,它自动有这样的方法:

 - (void)viewWillDisappear:(BOOL)animated; // Called when the view is dismissed, covered or otherwise hidden. Default does nothing - (void)viewDidDisappear:(BOOL)animated; // Called after the view was dismissed, covered or otherwise hidden. Default does nothing 

需要创建自己的这些方法的实现,这些方法将使用委托来判断CNContactPickerViewController View是否被解雇或将被解雇。 这是我的Objective-C这种实现的例子:

SKContactPickerViewController.h

  #import  @protocol SKContactPickerDelegate; @interface SKContactPickerViewController : CNContactPickerViewController @property (weak, nonatomic, nullable) id  delegate; @end @protocol SKContactPickerDelegate  @required - (void)contactPicker:(SKContactPickerViewController *)picker viewDidDisappear:(BOOL)animated; @optional - (void)contactPicker:(SKContactPickerViewController *)picker viewWillDisappear:(BOOL)animated; @end 

SKContactPickerViewController.m

 #import "SKContactPickerViewController.h" @implementation SKContactPickerViewController @dynamic delegate; - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; SEL selector = @selector(contactPicker:viewWillDisappear:); if ([self.delegate respondsToSelector:selector]) { [self.delegate contactPicker:self viewWillDisappear:animated]; } } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; SEL selector = @selector(contactPicker:viewDidDisappear:); if ([self.delegate respondsToSelector:selector]) { [self.delegate contactPicker:self viewDidDisappear:animated]; } } @end 

您正在使用联系人选择器的.m文件中的某个位置:

 - (void)addFromContacts { SKContactPickerViewController *contactPicker = [[SKContactPickerViewController alloc] init]; contactPicker.delegate = self; // contactPicker.displayedPropertyKeys = @[CNContactEmailAddressesKey]; // etc. // display controller [self presentViewController:contactPicker animated:YES completion:nil]; } 

最后委托方法:

 - (void)contactPicker:(SKContactPickerViewController *)picker didSelectContact:(CNContact *)contact { // your usual implementation } - (void)contactPicker:(SKContactPickerViewController *)picker viewDidDisappear:(BOOL)animated { // Present your UIAlertController here } 

它将允许在联系人选择器被解雇后呈现UIAlsertController 。 此外,这种方法仍然允许您使用常规委托方法从Contacts UI获取数据 – 委托属性仍然来自Apple实现。 那是@dynamic delegate; 用于说这个属性将由它的超类实现。 您只需使用两个添加的方法通过自己的SKContactPickerDelegate扩展CNContactPickerDelegate协议。