2016-04-12 31 views
7

Mam API, która zwraca numery telefonów w formacie: + 1415xxxxxxx (E164)Swift Korzystanie Kontakt Framework, wyszukiwania za pomocą numeru telefonu, aby nazwa i Image User

Teraz te numery są umieszczane w komórce UITableView i są prezentowane zgodnie z oczekiwaniami, jednak chciałbym móc przeszukiwać kontakty użytkowników w telefonie, aby sprawdzić, czy istnieje odpowiednik - jeśli tak, odeślij również imię, nazwisko i znane zdjęcie.

Patrząc na stronach Apple (https://developer.apple.com/library/watchos/documentation/Contacts/Reference/Contacts_Framework/index.html) muszę

import ContactsUI 

ale potem Im pewien, mogę załadować contactDB do słownika, a następnie wyszukać go? Mogę znaleźć wiele rzeczy na poszukiwania poprzez nazwy, a mniej na szukaniu poprzez numer:

let predicate = CNContact.predicateForContactsMatchingName("Sam") 

Im próbuje dostać się do funkcji, które można nazwać, że wyszuka PhoneNumber i daje mi się imię, FamilyName i Obraz.

func searchForContactUsingNumber(PhoneNumber: String) 
{ 

// Search Via phoneNumber 
    let store = CNContactStore() 
    let contacts = try store.unifiedContactsMatchingPredicate(CNContact.predicateForContactsMatchingPhoneNumber(PhoneNumber), keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey,CNContactImageData]) 

    return FirstName, GivenName,UIImage 

} 

Mam wrażenie, że robię to wstecz, ale nie wiem, która droga jest do przodu .. Jakieś pomysły?

+0

Co stanie się, gdy spróbujesz swojego kodu? Jakie błędy dostałeś i co nie działa? –

+0

Kod jest w ogóle nieprawidłowy, nie sądzę, że istnieje CNContact.predicateForContactsMatchingPhoneNumber, po prostu zaadaptowałem nazwę, aby zilustrować, co próbuję uzyskać. –

+0

Wygląda na to, że nie istnieje predykat umożliwiający podanie numeru telefonu i zwrócenie kontaktu. Prawdopodobnie dlatego, że jest to nowy interfejs API. Napisałem kod, który zwraca listę identyfikatorów kontaktów pasujących do numeru telefonu, który można następnie użyć do zwrócenia kontaktu. Czy to jest interesujące? –

Odpowiedz

8

W celu uzyskania tego przykładu górę i działa szybko użyłem następujących źródeł informacji:

Filter non-digits from string

https://stackoverflow.com/a/32700339/558933

http://www.appcoda.com/ios-contacts-framework/

bloku kodu poniżej zawiera upoważnienie sprawdź, bo musiałem go uruchomić, aby przetestować w symulatorze. Ten kod to tylko kontroler widoków widoków pojedynczego widoku, a do Storyboard można podłączyć UIButton do metody findContactInfoForPhoneNumber:, aby uruchomić. Dane wyjściowe odnoszą się do konsoli - musisz zastąpić te instrukcje print czymś innym.

Jeśli nie interesuje Cię pełny kod kontrolera widoku, po prostu spójrz na metodę searchForContactUsingPhoneNumber(phoneNumber: String). Przestrzegałem zaleceń Apple w dokumentach, aby asynchronicznie obsługiwać architekturę CNContact.

Kod paski wszystkie +, - i ( symbole, które mogą być w numer telefonu i po prostu pasuje cyfry tak, numer telefonu, można przejść do meczu musi być dokładnie taka sama.

// 
// ViewController.swift 
// ContactsTest 
// 
// Created by Robotic Cat on 13/04/2016. 
// 

import UIKit 
import Contacts 

class ViewController: UIViewController { 

    // MARK: - App Logic 
    func showMessage(message: String) { 
     // Create an Alert 
     let alertController = UIAlertController(title: "Alert", message: message, preferredStyle: UIAlertControllerStyle.Alert) 

     // Add an OK button to dismiss 
     let dismissAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) { (action) -> Void in 
     } 
     alertController.addAction(dismissAction) 

     // Show the Alert 
     self.presentViewController(alertController, animated: true, completion: nil) 
    } 

    func requestForAccess(completionHandler: (accessGranted: Bool) -> Void) { 
     // Get authorization 
     let authorizationStatus = CNContactStore.authorizationStatusForEntityType(CNEntityType.Contacts) 

     // Find out what access level we have currently 
     switch authorizationStatus { 
     case .Authorized: 
      completionHandler(accessGranted: true) 

     case .Denied, .NotDetermined: 
      CNContactStore().requestAccessForEntityType(CNEntityType.Contacts, completionHandler: { (access, accessError) -> Void in 
       if access { 
        completionHandler(accessGranted: access) 
       } 
       else { 
        if authorizationStatus == CNAuthorizationStatus.Denied { 
         dispatch_async(dispatch_get_main_queue(), {() -> Void in 
          let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings." 
          self.showMessage(message) 
         }) 
        } 
       } 
      }) 

     default: 
      completionHandler(accessGranted: false) 
     } 
    } 

    @IBAction func findContactInfoForPhoneNumber(sender: UIButton) { 

     self.searchForContactUsingPhoneNumber("(888)555-1212)") 
    } 

    func searchForContactUsingPhoneNumber(phoneNumber: String) { 

     dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), {() -> Void in 
      self.requestForAccess { (accessGranted) -> Void in 
       if accessGranted { 
        let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactImageDataKey, CNContactPhoneNumbersKey] 
        var contacts = [CNContact]() 
        var message: String! 

        let contactsStore = CNContactStore() 
        do { 
         try contactsStore.enumerateContactsWithFetchRequest(CNContactFetchRequest(keysToFetch: keys)) { 
          (contact, cursor) -> Void in 
          if (!contact.phoneNumbers.isEmpty) { 
           let phoneNumberToCompareAgainst = phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("") 
           for phoneNumber in contact.phoneNumbers { 
            if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber { 
             let phoneNumberString = phoneNumberStruct.stringValue 
             let phoneNumberToCompare = phoneNumberString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("") 
             if phoneNumberToCompare == phoneNumberToCompareAgainst { 
              contacts.append(contact) 
             } 
            } 
           } 
          } 
         } 

         if contacts.count == 0 { 
          message = "No contacts were found matching the given phone number." 
         } 
        } 
        catch { 
         message = "Unable to fetch contacts." 
        } 

        if message != nil { 
         dispatch_async(dispatch_get_main_queue(), {() -> Void in 
          self.showMessage(message) 
         }) 
        } 
        else { 
         // Success 
         dispatch_async(dispatch_get_main_queue(), {() -> Void in 
          // Do someting with the contacts in the main queue, for example 
          /* 
          self.delegate.didFetchContacts(contacts) <= which extracts the required info and puts it in a tableview 
          */ 
          print(contacts) // Will print all contact info for each contact (multiple line is, for example, there are multiple phone numbers or email addresses) 
          let contact = contacts[0] // For just the first contact (if two contacts had the same phone number) 
          print(contact.givenName) // Print the "first" name 
          print(contact.familyName) // Print the "last" name 
          if contact.isKeyAvailable(CNContactImageDataKey) { 
           if let contactImageData = contact.imageData { 
            print(UIImage(data: contactImageData)) // Print the image set on the contact 
           } 
          } else { 
           // No Image available 

          } 
         }) 
        } 
       } 
      } 
     }) 
    } 

} 
+1

Wow! Świetnie, dziękuję za pomoc! –

+0

Więc jestem bardzo blisko tego. Jeśli skopuję twój kod na moją szybką stronę i uruchomię: 'self.searchForContactUsingPhoneNumber (" + 1987654321 ") // Gdzie +1987654321 ma wpis adresu, podaje mi nazwę tego wpisu i szczegóły UIIamge. Zgodnie z oczekiwaniami, Dziękuję ' Jednak jeśli mogę umieścić ten sam kod do ' func Tableview (tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { ' funkcja, od razu dostać błąd: '[] błąd krytyczny: Indeks poza zakresem' Gdzie nie jest załadowana tablica kontaktów. Chciałbym zwrócić nazwę i obraz interfejsu użytkownika za pomocą krotki. –

+0

Nie mogę powiedzieć, co jest nie tak z komentarza, ale mogę zgadnąć. Kod wyraźnie działa, ale wygląda na to, że masz problem logiczny, w którym zwracasz dane "kontakt". Sposób działania kodu polega na dodaniu znalezionego 'contact' do swojego modelu danych, a następnie zaktualizowaniu tabeli za pomocą' reloadData' lub 'reloadRowsAtIndexPaths: withRowAnimation:' zamiast zwracania wartości. Wynika to z tego, że kod działa asynchronicznie poza główną kolejką. Polecam użyć debuggera i znaleźć miejsce, w którym kod się zawiesza, ale wygląda na to, że próbujesz uzyskać dostęp do wartości 'contacts' przed powrotem kodu. –

1

ContactList z ContactUI ram z klienta Tableview

import UIKit 

class ContactCell: UITableViewCell { 
    @IBOutlet weak var PersonNameLabel: UILabel! 

    @IBOutlet weak var PersonMobileNOLabel: UILabel! 

    @IBOutlet weak var PersonImage: UIImageView! 

    @IBOutlet weak var PersonEmailLabel: UILabel! 
} 

ContactViewController

import ContactsUI 

class ContactViewController: UIViewController,CNContactPickerDelegate,UITableViewDelegate,UITableViewDataSource{ 
var objects = [CNContact]() 
@IBOutlet weak var tableView: UITableView! 
override func viewDidLoad() { 
    super.viewDidLoad() 
    self.getContacts() 
} 
func getContacts() { 
    let store = CNContactStore() 

    switch CNContactStore.authorizationStatus(for: .contacts){ 
    case .authorized: 
     self.retrieveContactsWithStore(store: store) 

    // This is the method we will create 
    case .notDetermined: 
     store.requestAccess(for: .contacts){succeeded, err in 
      guard err == nil && succeeded else{ 
       return 
      } 
      self.retrieveContactsWithStore(store: store) 

     } 
    default: 
     print("Not handled") 
    } 

} 
func retrieveContactsWithStore(store: CNContactStore) 
{ 


let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactPhoneNumbersKey,CNContactImageDataKey, CNContactEmailAddressesKey] as [Any] 
    let request = CNContactFetchRequest(keysToFetch: keysToFetch as! [CNKeyDescriptor]) 
    var cnContacts = [CNContact]() 
    do { 
     try store.enumerateContacts(with: request){ 
      (contact, cursor) -> Void in 
      if (!contact.phoneNumbers.isEmpty) { 
      } 

      if contact.isKeyAvailable(CNContactImageDataKey) { 
       if let contactImageData = contact.imageData { 
        print(UIImage(data: contactImageData)) // Print the image set on the contact 
       } 
      } else { 
       // No Image available 

      } 
      if (!contact.emailAddresses.isEmpty) { 
      } 
      cnContacts.append(contact) 
      self.objects = cnContacts 
     } 
    } catch let error { 
     NSLog("Fetch contact error: \(error)") 
    } 

    NSLog(">>>> Contact list:") 
    for contact in cnContacts { 
     let fullName = CNContactFormatter.string(from: contact, style: .fullName) ?? "No Name" 
     NSLog("\(fullName): \(contact.phoneNumbers.description)") 
    } 
    self.tableView.reloadData() 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return self.objects.count 
} 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! ContactCell 
    let contact = self.objects[indexPath.row] 
print("theis my contact arrau \(self.objects.count)") 
    let formatter = CNContactFormatter() 
    cell.PersonNameLabel.text = formatter.string(from: contact) 
if let actualNumber = contact.phoneNumbers.first?.value as? CNPhoneNumber { 
    //Get the label of the phone number 

    //Strip out the stuff you don't need 
    print(actualNumber.stringValue) 
cell.PersonMobileNOLabel.text = actualNumber.stringValue 
} 
else{ 
    cell.PersonMobileNOLabel.text = "N.A " 
} 
if let actualEmail = (contact as AnyObject).emailAddresses?.first?.value as String? { 
    print(actualEmail) 
    cell.PersonEmailLabel.text = actualEmail 
} 
else{ 
    cell.PersonEmailLabel.text = "N.A " 
} 
if let imageData = contact.imageData { 
    //If so create the image 
    let userImage = UIImage(data: imageData) 
    cell.PersonImage.image = userImage; 
} 

else{ 
    cell.PersonImage.image = UIImage (named: "N.A") 
} 
    return cell 
} 
} 
0

prawidłowy sposób jest do numerów indeksu we własnej bazie danych, dzięki czemu można odnośnika do identyfikatora kontaktowego.