2016-04-12 8 views
7

Ich habe eine API, die Telefonnummern im Format zurückgibt: + 1415xxxxxxx (E164)Swift Kontakte verwenden Framework Suche Telefonnummer mit Name und User Image bekommen

Gerade jetzt diese Zahlen eine Zelle eines UITableView setzen in und werden wie erwartet präsentiert, aber ich möchte in der Lage sein, die Kontakte des Benutzers auf dem Telefon zu suchen, um zu sehen, ob es eine Übereinstimmung gibt - wenn ja, auch den Vornamen, den Nachnamen und das bekannte Foto zurückgeben.

Mit Blick auf den Apple-Seiten (https://developer.apple.com/library/watchos/documentation/Contacts/Reference/Contacts_Framework/index.html) Ich

brauchen
import ContactsUI 

aber dann unsicher Im, lade ich die KontakteDB in ein Wörterbuch und dann danach suchen? Ich kann viele Dinge auf der Suche über Namen und weniger auf der Suche über Nummer finden:

let predicate = CNContact.predicateForContactsMatchingName("Sam") 

Im Versuch, auf eine Funktion zu erhalten, die ich anrufen kann, die die Phonesucht mit und gibt mir die Firstfamily zurück und Bild.

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 

} 

Ich habe das Gefühl, dass ich rückwärts renne, aber nicht sicher, welcher Weg nach vorne geht. Irgendwelche Ideen?

+0

Was passiert, wenn Sie Ihren Code ausprobieren? Welche Fehler haben Sie und was funktioniert nicht? –

+0

Der Code stimmt überhaupt nicht, ich denke nicht, dass es ein CNContact.predicateForContactsMatchingPhoneNumber gibt, ich habe gerade Name angepasst, um zu illustrieren, was ich versuche zu bekommen. –

+0

Es scheint kein Prädikat zu sein, mit dem Sie eine Telefonnummer weitergeben und einen Kontakt zurückgeben können. Wahrscheinlich, weil dies eine neue API ist. Ich habe einen Code geschrieben, der eine Liste von Kontaktbezeichnern zurückgibt, die mit einer Telefonnummer übereinstimmen, mit der Sie dann einen Kontakt zurückgeben können. Ist das von Interesse? –

Antwort

8

Um dieses Beispiel zu erhalten up-and-Laufen schnell habe ich die folgenden Quellen von Informationen:

Filter non-digits from string

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

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

Der Codeblock unten enthält die Berechtigung check, weil ich es zum Funktionieren bringen musste, um im Simulator zu testen. Der Code ist nur der Ansichts-Controller für Single-View-Apps und Sie können eine UIButton im Storyboard mit der findContactInfoForPhoneNumber:-Methode verbinden, um zu erhalten, ob sie ausgeführt werden soll. Die Ausgabe erfolgt an die Konsole - Sie müssen diese print Anweisungen durch etwas anderes ersetzen.

Wenn Sie nicht an der Vollansicht Controller-Code interessiert sind, dann schauen Sie sich einfach die searchForContactUsingPhoneNumber(phoneNumber: String) Methode. Ich habe Apples Empfehlung in den Dokumenten gefolgt, das -Framework asynchron auszuführen.

Die Code-Streifen all +, - und ( Symbole, die in einer Telefonnummer sein könnten und paßt nur die Ziffern, so dass die Telefonnummer, die Sie in geben zu müssen genau gleich sein lassen.

// 
// 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! Super, danke für deine Hilfe! –

+0

Also ich bin sehr nah dran, das zu bekommen. Wenn ich Ihren Code in meine Swift-Seite kopieren und ausführen: 'self.searchForContactUsingPhoneNumber (" + 1987654321 ") // Wo +1987654321 hat eine Adresse Eintrag gibt mir die Adresse Eintragsname und UIIamge Details. Wie erwartet, Danke ' Allerdings, wenn ich den gleichen Code in das ' func Tableview setzen (Tableview: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { ' Funktion, habe ich sofort Fehlermeldung erhalten: '[] Schwerwiegender Fehler: Index außerhalb des Bereichs Wo es das Kontakte-Array nicht geladen ist. Ich wollte den Namen und das UI-Bild mit einem Tupel zurückgeben. –

+0

Ich kann nicht sagen, was aus dem Kommentar schief geht, aber ich kann es erraten. Der Code funktioniert eindeutig, aber es klingt, als ob Sie ein logisches Problem haben, bei dem Sie die "Kontakt" -Daten zurückgeben. Die Funktionsweise des Codes besteht darin, dass Sie den gefundenen "Kontakt" in Ihr Datenmodell einfügen und dann die Tabelle mit 'reloadData' oder' reloadRowsAtIndexPaths: withRowAnimation: 'aktualisieren, anstatt einen Wert zurückzugeben. Dies liegt daran, dass der Code außerhalb der Hauptwarteschlange asynchron ausgeführt wird. Ich empfehle Ihnen, den Debugger zu verwenden und zu finden, wo der Code abstürzt, aber es klingt, als ob Sie versuchen, auf den Wert "Kontakte" zuzugreifen, bevor der Code zurückgegeben wurde. –

1

Contact mit ContactUI Rahmen mit benutzerdefinierten 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

Der richtige Weg ist zu indizieren Telefonnummern in Ihrer eigenen Datenbank, so dass Sie für die Kontaktkennung Nachschlag kann.