Ios 从未调用CNContactPickerDelegate的contactPickerDidCancel

Ios 从未调用CNContactPickerDelegate的contactPickerDidCancel,ios,swift,Ios,Swift,当我使用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 contactPickerDi

当我使用
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
后执行此操作

我可以在
viewdide
中使用一些逻辑,但似乎应该有一种更干净的方法

剩下的唯一委托方法是:

/*!
 * @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
    }

我同意,当选择器自行关闭时,您需要以编程方式关闭选择器,这似乎很奇怪。顺便说一句,对于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开发人员。下面是处理这种情况的另一种方法:由于
CNContactPickerViewController
UIViewController
类的后代,因此它自动具有以下方法:

- (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
视图是否已解除或即将解除。以下是我的Objective-C实施示例:

SKContactPickerViewController.h

在.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实现中。即
@动态委托用于表示此属性将由其超类实现。您只需通过自己的
SKContactPickerDelegate
扩展
CNContactPickerDelegate
协议,并添加两个方法。

为什么选择联系人时会调用
contactPickerDidCancel
?@Adeel很好的问题,不确定,但确实如此。只有当一个联系人有一个关联的号码时,我才知道。这就是我现在所知道的,但从来没有显示过警报。我相信这是因为这个委托方法是在联系人选取器已经被显示的时候被调用的。如果你看代码,它是在picker.dimiss的完成处理程序中被调用的,所以它发生在选取器离开屏幕之后,否则,当另一个vc以模态方式呈现时,您将在日志中得到一个关于尝试呈现模态的错误。这是我正在运行的生产代码的一个版本,因此我知道它是有效的(我实际上将电子邮件作为一个操作表呈现,以便您可以选择一个,但概念上是相同的,我在我的程序中插入了上面的代码,并且它是有效的)。啊!你说得对。我没有看到
选择器。请退出
行。我不得不使用
picker.dismissViewControllerAnimated
,它现在正在工作。看起来很奇怪,当它自行关闭时,您需要以编程方式调用它。
- (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
}