2017-10-14 125 views
0

我試圖從通訊錄中選擇聯繫人號碼,而當我嘗試爲其更新邏輯時,它未能選擇地址簿,而是當我單擊號碼時,它正在撥打這個號碼。當我嘗試選擇號碼時,代表團不會被呼叫。下面的代碼雖然很長,但我試圖描述一切(省略不相關的代碼),所以你得到了這個問題的想法。聯繫人選取器的代表設置不正確

因此,複雜的事情是,我有一個HomeViewController,這一點我從一個叫HomeHelper(與UITableView的一個UIView)輔助設置中的所有數據。我確實從一個名爲WidgetView的視圖添加了一個UITableViewCell,並且正在設置的數據是從WidgetHelper。 WidgetHelper將加載一個名爲WidgetProductAHelper(以及稱爲WidgetProductAView的視圖)的UITableViewCell。

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

看這個功能:

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

要創建的CNPicker該函數內,一旦它退出openUserAddressBook功能,CNPicker得到釋放。

最好是讓CNPicker屬於AddressBookHelper頂部的一個屬性。

例如爲:

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... 

} 
+0

嗨@Michael Dautermann,非常感謝你,但它仍然不適合我。我已經更新了這個問題供您參考。 –

+0

你現在正在做的事情,''CNPicker'屬性的每個調用返回一個'CNContactPickerViewController()',***在每次引用時創建一個新的CNContactPickerViewController。您需要創建一次CNContactPickerViewController,然後將其設置爲一個屬性,並且它會一直存在。 –

+0

oic,它現在正常工作,謝謝@Michael Dautermann :) –

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

+0

嗨@Sergnsk,哎呀抱歉,我剛剛更新了代碼,我從我的項目中複製了錯誤的代碼,感謝您的注意;( –