2017-07-25 107 views
2

我已經在視圖控制器中成功實現了iOS10提供的CNContactPickerViewControllerFacebookUI,因此我可以讓用戶選擇多個聯繫人來邀請事件。我試圖通過實現委託模式來減小這個單一視圖控制器的大小,並將其卡在黑屏上。我查看了一些資源,並認爲我正在調用委託並相應地定義協議。我有一個視圖控制器,CreateEventViewController,它實現了我自定義的ContactsToInviteDelegate。該協議如下:在Swift中重構使用委託模式的CNContactPicker UI代碼

protocol ContactsToInviteDelegate : class { 
    //array of array of KV-pairs where inner array is {"email":"[email protected]", "phone": "+18965883371"} 
    //array of JSON objects to upload 
    func contactsToInvite(_ contactsStructure: [[String:String]]) 
} 

我ContactPickerViewController自定義的類如下:

class ContactPickerViewController: UIViewController, CNContactPickerDelegate { 
    //class variables 
    let phoneNumberKit = PhoneNumberKit() 
    weak var delegate: ContactsToInviteDelegate? 
    var contactsToSendInvitesTo = [[String:String]]() 

    func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) { 
     contacts.forEach { contact in 
      let phoneNum = contact.phoneNumbers.first 
      var stringPhoneNumber = String() 
      do{ 
       let phoneNumber = try self.phoneNumberKit.parse((phoneNum?.value.stringValue)!, withRegion: "US", ignoreType:true) 
      stringPhoneNumber = "+1\(phoneNumber.adjustedNationalNumber())" 
      print(stringPhoneNumber) 
      } 
      catch { 
       print("phone number parsing error") 
      } 

      let contactDisplayName = contact.givenName 
      print("displayName: \(contactDisplayName)") 

      let contactEmail = contact.emailAddresses.first?.value ?? "" 
      print("email: \(contactEmail)") 

      self.contactsToSendInvitesTo.append(["email":contactEmail as String, "phone":stringPhoneNumber]) 
     } 
     delegate?.contactsToUpload(self.contactsToSendInvitesTo) 
    } 

    func contactPickerDidCancel(_ picker: CNContactPickerViewController) { 
     print("cancel contact picker") 
    } 

    func contactPicker(_ picker: CNContactPickerViewController,didSelectContactProperties contactProperties: [CNContactProperty]) { 

    } 

} 

而在CreateEventViewController我打電話委託當我點擊邀請用戶按鈕和實現的方法該協議只是試圖打印最終結構顯示聯繫人的電子郵件和電話號碼發送邀請:

func selectContactsPicker() { 
     let cnPicker = ContactPickerViewController() 
     cnPicker.delegate = ContactPickerViewController() as? ContactsToInviteDelegate 
     self.present(cnPicker, animated:true, completion:nil) 

} 

func contactsToInvite(_ contactsStructure: [[String : String]]) { 
    print(contactsStructure) 
} 

此代碼無需重構即可嘗試使用之前工作的委託模式。我在一個單一的視圖控制器中擁有所有這些功能,但是所有這些文件本身所需的邏輯都超出了400多行。我現在的問題是,嘗試重構使用委託模式後,當我點擊按鈕觸發selectContactsPicker我所看到的只是一個黑屏。我不知道我做錯了什麼,但我有一種感覺,就是這個功能本身。我不太清楚這個函數的主體應該是什麼,以便將責任委託給正確的控制器,或者如何正確顯示它。我看到的示例使用了故事板和賽格,例如this。我研究了其他使用代表的例子,但我認爲我的問題有點過於具體,我不知道如何以更一般的方式提問。如果我這樣做,我可能不會有這個問題開始,因爲那時我可能會正確理解如何實現委託模式。

+0

您正在實例化ContactPickerViewController,但它沒有內容,因此您將會看到一個黑屏。您需要以編程方式或從故事板或XIB加載一些內容。在重構代碼之前,您是如何定義視圖內容的? – Dale

+0

@Dale之前我簡單地'let cnPicker = CNContactPickerViewController()'這是ContactsUI的直接。現在我試圖使用ContactsUI中的數據來委託代碼,但不確定如何或在何處實例化ContactsUI – kinghenry14

回答

1

委託不一定是視圖控制器。當視圖控制器管理需要委託的元素時,這是一種方便的模式 - 而不是實例化單獨的對象,而只是讓視圖控制器實現協議。

有很多方法可以管理增長過大的不規則視圖控制器。

一個簡單的方法是使用擴展。要委託協議添加到現有的視圖控制器:

extension SomeViewController : CNContactPickerDelegate { 

    ... implement contact picker delegate methods 

} 

這可以很好地compartmentalise你的源代碼,使其更容易閱讀。

如果你想使用一個單獨的類實例作爲委託,那也可以很容易地完成。

聲明你的委託類,無論是在同一個源文件或其他:

class MyPickerDelegate : NSObject, CNContactPickerDelegate { 

    ... implement contact picker delegate methods 

} 

注意到類必須從NSObject的繼承,但並不需要是一個UIViewController。

在你火了聯繫人選擇器的代碼:

picker = CNContactPickerViewController() 
self.pickerDelegate = MyPickerDelegate() 
picker.delegate = self.pickerDelegate 
self.present(picker, animated: true) 

注意選擇器視圖控制器僅保持一個弱引用的委託,所以你必須確保保持強大的參考對象的某個地方。在這裏,我使用屬性選擇器DeleteDelegate