从未调用过CNContactPickerDelegate的contactPickerDidCancel

时间:2016-10-25 17:06:29

标签: 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 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)

2 个答案:

答案 0 :(得分:3)

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

    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
    }

答案 1 :(得分:1)

我同意您似乎很奇怪,当您自行关闭选择器时,需要以编程方式将其关闭。顺便说一句,对于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类的后代,因此它自动具有以下方法:

- (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 <ContactsUI/ContactsUI.h>

    @protocol SKContactPickerDelegate;

    @interface SKContactPickerViewController : CNContactPickerViewController

    @property (weak, nonatomic, nullable) id <CNContactPickerDelegate, SKContactPickerDelegate> delegate;

    @end


    @protocol SKContactPickerDelegate <CNContactPickerDelegate>

    @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;用于表示此属性将由其超类实现。您只需使用两个添加的方法通过自己的CNContactPickerDelegate扩展SKContactPickerDelegate协议即可。