联系人选择器的授权没有正确设置

时间:2017-10-14 11:57:35

标签: ios swift delegates

我正在尝试从地址簿中选择联系号码,当我尝试修改它的逻辑时,它无法选择地址簿,相反,当我点击该号码时,它会拨打该号码。在我尝试选择号码时,代表团不会被呼叫。

下面的代码很长,但我试图描述所有内容(省略不相关的代码),这样你就可以了解问题。

所以,复杂的事情是,我有一个 HomeViewController ,我从一个名为 HomeHelper 的帮助器(一个带有UITableView的UIView)中设置了所有数据。我从名为 WidgetView 的视图中添加了一个UITableViewCell,并且数据是从 WidgetHelper 设置的。 WidgetHelper将加载名为 WidgetProductAHelper 的UITableViewCell(以及名为WidgetProductAView的视图)。

WidgetProductAView包含一个图像按钮,当我单击该按钮时,它应该显示联系人选择器。我尝试将逻辑分离到一个名为 AddressBookHelper 的新类,因此我可以在任何地方使用它而不需要任何冗余。它确实成功显示地址簿,但当我尝试单击其中一个时,它将重定向到详细联系人屏幕,而不是调用 peoplePickerNavigationController 方法。我为此设定了代表团但仍然没有工作。

当我尝试仅在一个类中编写它们时,这个功能确实有效。可能有什么不对?请帮忙弄清楚,我怀疑使用助手有一些不正确的实施,但无法解决这个问题。感谢。

HomeViewController.swift

class HomeViewController: UIViewController {

    var dataSource : UITableViewDataSource?
    var delegate : UITableViewDelegate?

    override func viewDidLoad() {
        //
        let helper = HomeHelper()

        helper.homeViewController = self

        dataSource = helper
        delegate = helper

        tableView.dataSource = dataSource
        tableView.delegate = delegate
    }

}

HomeHelper.swift

class HomeHelper: UITableViewDataSource, UITableViewDelegate, WidgetViewDelegate {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "WidgetView", for: indexPath) as? UITableViewCell else {
            return UITableViewCell()
        }

        if let customView = cell.customView as? WidgetView {
            let helper = WidgetHelper()
            customView.helperDataSource = helper
            customView.helperDelegate = helper
            customView.delegate = self
            helper.controller = customView

            customView.initCell()

            return cell
        }
    }

    // MARK: - WidgetViewDelegate

    func presentOnHome(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Swift.Void)? = nil) {
        self.homeViewController?.present(viewControllerToPresent, animated: animated, completion: completion)
    }

}

WidgetView.swift

protocol WidgetViewDelegate {
    func presentOnHome(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Swift.Void)?)
}

class WidgetView: NSObject {

    var delegate: WidgetViewDelegate?

    var helperDataSource: WidgetViewHelperDataSource?
    var helperDelegate: WidgetViewHelperDelegate?

    func initCell() {
        //
        tableView.dataSource = helperDataSource
        tableView.delegate = helperDelegate
    }

    func presentOnHome(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Swift.Void)?) {
        delegate?.presentOnHome(viewControllerToPresent, animated: animated, completion: completion)
    }

}

WidgetHelper.swift

class WidgetHelper: UITableViewDataSource, UITableViewDelegate, WidgetProductAHelperDelegate {

    var controller: WidgetView?

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "WidgetProductAView", for: indexPath) as? UITableViewCell else {
            return UITableViewCell()
        }

        if let customView = cell.customView as? WidgetProductAHelper {
            customView.parentHelper = self
            customView.delegate = self
            customView.initCell()

            return cell
        }
    }

    // MARK: - WidgetProductAHelperDelegate

    func presentOnHome(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Swift.Void)? = nil) {
        self.homeViewController?.present(viewControllerToPresent, animated: animated, completion: completion)
    }

}

WidgetProductAHelper.swift

protocol WidgetProductAHelperDelegate {
    func presentOnHome(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Swift.Void)?)
}

class WidgetProductAHelper: UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var contactImageButton: UIButton!

    var parentHelper: WidgetHelper?
    var delegate: WidgetProductAHelperDelegate?

}

func initCell() {
    //
    contactImageButton.isUserInteractionEnabled = true;
    contactImageButton.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(WidgetProductAHelper.contactImageButtonTapped(_:))))
}

func contactImageButtonTapped(_ sender: UIGestureRecognizer) {
    let addressBookHelper = AddressBookHelper()
    addressBookHelper.contactImageButton = contactImageButton
    addressBookHelper.completion = { (result) in
        switch result {
        case .presentOnHome(let viewControllerToPresent) :
            self.parentHelper?.presentOnHome(viewControllerToPresent, animated: true, completion: nil)

            break
        }
    }
    addressBookHelper.addressBookButtonTapped()
}

AddressBookHelper.swift

正如您在下面的代码中所看到的,我已将CNPicker的委托设置为类,但不会调用委托方法。对于像displayErrorMessage()和displayPromptForAddressBookRequestAccess()这样的其他东西,它可以很好地显示弹出窗口。

enum AddressBookActionResult {
    case presentOnHome(viewControllerToPresent: UIViewController)
}

class AddressBookHelper: NSObject, CNContactPickerDelegate {

    var completion: ((AddressBookActionResult) -> ())?

    var contactImageButton: UIButton?

    @available(iOS 9.0, *)
    var CNPicker: CNContactPickerViewController {
        return CNContactPickerViewController()
    }

    func addressBookButtonTapped() {
        switch CNContactStore.authorizationStatus(for: .contacts) {
        case .denied, .restricted:
            // displayErrorMessage()
            break
        case .authorized:
            openUserAddressBook()
            break
        case .notDetermined:
            // displayPromptForAddressBookRequestAccess()
            break
        }
    }

    func openUserAddressBook() {
        if #available(iOS 9.0, *) {
            CNPicker.delegate = self
            completion?(.presentOnHome(viewControllerToPresent: CNPicker))
        }
    }


    // MARK: - CNContactPickerDelegate

    @available(iOS 9.0, *)
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
        // This method doesn't get called
        //...
    }

}

2 个答案:

答案 0 :(得分:3)

看看这个功能:

func openUserAddressBook() {
        let CNPicker: CNContactPickerViewController = CNContactPickerViewController()
        CNPicker.delegate = self
        completion?(.presentOnHome(viewControllerToPresent: CNPicker))
    }

您正在该功能中创建CNPicker,只要退出 openUserAddressBook功能,CNPicker就会被释放。

最好让CNPicker属于AddressBookHelper顶部的属性。

e.g:

class AddressBookHelper: NSObject, CNContactPickerDelegate {

    // create CNContactPickerViewController once and only once
    let cnPicker = CNContactPickerViewController()

    var completion: ((AddressBookActionResult) -> ())?

    override init()
    {
        super.init()

        // and set the delegate of the picker to this Helper class
        self.cnPicker.delegate = self
    }

    func openUserAddressBook() {
        completion?(.presentOnHome(viewControllerToPresent: self.cnPicker))
    }

    func contactPicker(_ picker: CNContactPickerViewController,
                   didSelect contact: CNContact)
    {
        print("selected a contact!")
    }

    // and other delegate methods can be implemented and they
    // will be called...

}

答案 1 :(得分:0)

CNContactPickerDelegate没有方法

 func peoplePickerNavigationController(_ peoplePicker: ABPeoplePickerNavigationController, didSelectPerson person: ABRecord) {
        // This method doesn't get called
        //...
 }

它改为

func contactPicker(CNContactPickerViewController, didSelect: CNContact)
Called after a contact has been selected by the user.

您可以在此处查看委托方法的完整列表 https://developer.apple.com/documentation/contactsui/cncontactpickerdelegate