You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为CNContactPickerViewController实现两个不同的CNContactPickerDelegate

同一视图控制器中使用两种CNContactPickerViewController行为的解决方案

你提到的隔离代理的思路完全可行,核心就是创建两个独立的代理类,各自实现对应行为的CNContactPickerDelegate方法,以此区分两种选择器的逻辑,无需对CNContactPickerViewController本身做子类化修改。

步骤1:创建独立的代理类

分别实现两个代理类,各自处理一种选择器行为,通过闭包将选中结果回调给视图控制器:

单个联系人选择代理

class SingleContactPickerDelegate: NSObject, CNContactPickerDelegate {
    private let completion: (CNContact) -> Void
    
    init(completion: @escaping (CNContact) -> Void) {
        self.completion = completion
        super.init()
    }
    
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
        picker.dismiss(animated: true)
        completion(contact)
    }
    
    func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
        picker.dismiss(animated: true)
    }
}

多个联系人选择代理

class MultipleContactPickerDelegate: NSObject, CNContactPickerDelegate {
    private let completion: ([CNContact]) -> Void
    
    init(completion: @escaping ([CNContact]) -> Void) {
        self.completion = completion
        super.init()
    }
    
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
        picker.dismiss(animated: true)
        completion(contacts)
    }
    
    func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
        picker.dismiss(animated: true)
    }
}

步骤2:在视图控制器中使用

在视图控制器中声明属性持有代理实例(避免因弱引用导致代理被提前释放),分别初始化不同的选择器并绑定对应代理:

class YourViewController: UIViewController {
    // 持有代理实例,防止被提前释放
    private var singleContactDelegate: SingleContactPickerDelegate?
    private var multipleContactDelegate: MultipleContactPickerDelegate?
    
    // 打开单个联系人选择器
    func presentSingleContactPicker() {
        let picker = CNContactPickerViewController()
        let delegate = SingleContactPickerDelegate { [weak self] selectedContact in
            // 处理单个联系人选中逻辑
            self?.handleSingleContact(selectedContact)
            self?.singleContactDelegate = nil // 用完释放代理
        }
        singleContactDelegate = delegate
        picker.delegate = delegate
        present(picker, animated: true)
    }
    
    // 打开多个联系人选择器
    func presentMultipleContactPicker() {
        let picker = CNContactPickerViewController()
        let delegate = MultipleContactPickerDelegate { [weak self] selectedContacts in
            // 处理多个联系人选中逻辑
            self?.handleMultipleContacts(selectedContacts)
            self?.multipleContactDelegate = nil // 用完释放代理
        }
        multipleContactDelegate = delegate
        picker.delegate = delegate
        present(picker, animated: true)
    }
    
    // 单个联系人选中后的业务逻辑
    private func handleSingleContact(_ contact: CNContact) {
        // 这里写你的具体处理代码,比如提取联系人信息
    }
    
    // 多个联系人选中后的业务逻辑
    private func handleMultipleContacts(_ contacts: [CNContact]) {
        // 这里写你的具体处理代码
    }
}

关键注意事项

  • 代理类必须继承自NSObject:因为CNContactPickerDelegate是基于Objective-C的协议,只有NSObject子类才能正确实现代理方法。
  • 必须持有代理实例:UIKit的代理属性都是弱引用,如果不在视图控制器中保留强引用,代理对象会在选择器弹出后被立即释放,导致代理方法无法触发。

这个方案完全隔离两种选择器的行为逻辑,代码职责清晰,避免了子类化带来的耦合问题,完全符合你想要的“仅隔离代理”的需求。

内容的提问来源于stack exchange,提问作者benc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:01:34