For some reason, I keep getting duplicates on a lot of the contacts that I'm able to access with my code. Any reason why?
var error: Unmanaged<CFError>?
addressBook = ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue()
if let people = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(self.addressBook, nil, ABPersonSortOrdering(kABPersonSortByFirstName)).takeRetainedValue() as? NSArray {
for record in people {
//var contactPerson: ABRecordRef = record
var contactName: String = ABRecordCopyCompositeName(record).takeRetainedValue() as String
var number = ""
var phones: ABMultiValueRef = ABRecordCopyValue(record, kABPersonPhoneProperty).takeRetainedValue()
for j in 0..<ABMultiValueGetCount(phones) {
number = ABMultiValueCopyValueAtIndex(phones, j).takeRetainedValue() as! String
break
}
if (number != "") {
var newPerson = personInfo(name: contactName, number: number)
allContacts.append(newPerson)
}
self.tableView.reloadData()
}
}
James Richards Please Use the Contacts frame work instead of using address book.
First you shoud add Contacts framework through Build Phases->Link Binary with Libraries->add(click +)->choose contacts framework
import Contacts
Then
let status = CNContactStore.authorizationStatusForEntityType(.Contacts)
if status == .Denied || status == .Restricted {
// user previously denied, so tell them to fix that in settings
return
}
// open it
let store = CNContactStore()
store.requestAccessForEntityType(.Contacts) { granted, error in
guard granted else {
dispatch_async(dispatch_get_main_queue()) {
// user didn't grant authorization, so tell them to fix that in settings
print(error)
}
return
}
// get the contacts
var contacts = [CNContact]()
let request = CNContactFetchRequest(keysToFetch:[CNContactIdentifierKey, CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)])
do {
try store.enumerateContactsWithFetchRequest(request) { contact, stop in
contacts.append(contact)
}
}
catch {
print(error)
}
// do something with the contacts array (e.g. print the names)
let formatter = CNContactFormatter()
formatter.style = .FullName
for contact in contacts {
print(formatter.stringFromContact(contact))
}
}
The Output Results
Optional("John Appleseed")
Optional("Kate Bell")
Optional("Anna Haro")
Optional("Daniel Higgins Jr.")
Optional("David Taylor")
Optional("Hank M. Zakroff")
Link 1
Apple Document
Contacts
Related
Having problems retrieving a record from CloudKit..
My firstName and lastName of my CKRecord are showing up as "N/A" which the safety value from a nil coalescing as you'll see below
I double and triple checked (and beyond) that all the spellings were right.. so I'm good there. Here is my retrieve method..
func getProfile() {
//GETTING USER RECORD ID
CKContainer.default().fetchUserRecordID { id, error in
guard let id = id, error == nil else {
print(error?.localizedDescription)
return }
//GETTING RECORD ID
CKContainer.default().publicCloudDatabase.fetch(withRecordID: id) { record, error in
guard let record = record, error == nil else { return }
let profileReference = record["userProfile"] as! CKRecord.Reference
let profileRecordID = profileReference.recordID
print("Profile reference is",profileReference)
//PASSING REFERENCE TO GET CLIENT SIDE MODEL
CKContainer.default().publicCloudDatabase.fetch(withRecordID: profileRecordID) { profileRecord, error in
guard let profileRecord = profileRecord, error == nil else {
print(error!.localizedDescription)
return
}
//FOR SOME REASON MY PROFILE IS NOT RECEIVING THE RIGHT VALUES FOR FIRST AND LAST NAME, IT JUST SHOWS "N/A"
DispatchQueue.main.async {
let profile = Profile(record: profileRecord)
print("Retrieved Record is: ",profileRecord)
print("Retrieved name is: \(profile.firstName)")
firstName = profile.firstName
lastName = profile.lastName
}
}
}
}
}
And here is the model..
struct Profile {
let profileID: CKRecord.ID
let firstName: String
let lastName: String
init(record: CKRecord) {
profileID = record.recordID
firstName = record["firstName"] as? String ?? "N/A"
lastName = record["lastName"] as? String ?? "N/A"
}
}
I have two entities of Mobile and User in which Mobile has attribute name and user also has a attribute of name. User can has multiple mobile but mobile has can only one user. Scenario is that when ever I enter a name for user which is already present in User entity it should update that user.mobile set rather than duplicating a new user.
These are my save and fetch functions
func save () {
if context.hasChanges {
do {
try context.save()
print("saved succesfully")
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
func fetch<T: NSManagedObject>( _ objectType: T.Type) -> [T] {
let entityName = String(describing: objectType)
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
do {
let fetchedObjects = try context.fetch(fetchRequest) as? [T]
return fetchedObjects ?? [T]()
} catch {
print(error)
return [T]()
}
}
This is how i am adding
users = persistenceManager.fetch(User.self)
if users.count > 1 {
for val in users {
if val.name == "Umar" {
val.addToDevice(device)
device.user = val
persistenceManager.save()
}
else if val.name != nil {
user.name = "Umar"
user.addToDevice(device)
device.user = user
persistenceManager.save()
}
}
Your question lacks some details. BUt let me assume I understand you correctly.
let userName = "some name from user input"
let user = MOUser.getUser(context, name: userName, createIfMissing: true)
// here you have user with name required and not duplicated if already exists
device.user = user
And add static function either to your user class or to db coordinator
static func getUser(moc: NSMaagedObjectContext, name: String, createIfMissing: Bool) -> MOUser? {
let request: NSFetchRequest<MOUser> = MOUser.fetchRequest()
request.predicate = NSPredicate(format: "\(#keyPath(MOUser.name)) = %#", name)
request.fetchLimit = 1
var result: MOUser? = (try? moc.fetch(request))?.first
if result == nil && createIfMissing {
result = MOUser(context: moc)
result?.name = name
}
return result
}
Trying unsuccessfully to get a contact match providing contact Identifier. I desire to return contact, then to use the image associated with it. I am getting a nil match. thank you. This code I got from a demo, I'm kinda new to programming
import Contacts
var contact = CNContact()
var contactStore = CNContactStore()
let foundContact = getContactFromID("94AAD3B1-E9E1-48C9-A796-F7EC1014230A")
func getContactFromID(contactID: String) -> CNContact {
AppDelegate.getAppDelegate().requestForAccess { (accessGranted) -> Void in
if accessGranted {
let predicate = CNContact.predicateForContactsWithIdentifiers([contactID])
let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactImageDataKey, CNContactImageDataAvailableKey]
var contacts = [CNContact]()
var message: String!
let contactsStore = AppDelegate.getAppDelegate().contactStore
do {
contacts = try contactsStore.unifiedContactsMatchingPredicate(predicate, keysToFetch: keys)
if contacts.count == 0 {
message = "No contacts were found matching the given name."
}
}
catch {
message = "Unable to fetch contacts."
}
if message != nil {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
Utility.showAlert(nil, message: message)
})
} else {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.contact = contacts[0]
print("self.contact: \(self.contact)")
})
}
}
}
return self.contact
}
I solved it :), I removed the dispatch_async stuff, works now: here is fixed code.
func getContactFromID(contactID: String) -> CNContact {
AppDelegate.getAppDelegate().requestForAccess { (accessGranted) -> Void in
if accessGranted {
let predicate = CNContact.predicateForContactsWithIdentifiers([contactID])
let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactImageDataKey, CNContactImageDataAvailableKey]
var contacts = [CNContact]()
var message: String!
let contactsStore = AppDelegate.getAppDelegate().contactStore
do {
contacts = try contactsStore.unifiedContactsMatchingPredicate(predicate, keysToFetch: keys)
if contacts.count == 0 {
message = "No contacts were found matching the given name."
}
}
catch {
message = "Unable to fetch contacts."
}
self.contact = contacts[0]
}
}
return self.contact
}
I want to be able to check if an email address is already been used (so if somebody put test1#test.com but another user already registered with that email account).
I have a simple test if it has NOT been used an image view shows a green arrow, if it HAS been used then it is red x
when I create the user I use the following code
FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user, error) in
if error == nil {
self.ref.child("userEmails").child((user?.uid)!).setValue(email)
FIRAuth.auth()!.signIn(withEmail: email,
password: password)
} else {
//registration failure
}
what I am trying to do to check is
func checkIfEmailExists(textField: UITextField) {
let ref = FIRDatabase.database().reference()
let email = firstContainerTextField.text ?? ""
ref.child("userEmails").queryEqual(toValue: email)
.observe(.value, with: { snapshot in
if (self.firstContainerTextField.text?.isEmpty)! {
self.firstContainerImage.image = UIImage.init(named: "emptyBlue.png")
} else if !(self.firstContainerTextField.text?.isEmpty)! && !snapshot.exists() {
self.firstContainerImage.image = UIImage.init(named: "redEx.png")
} else if snapshot.exists() {
self.firstContainerImage.image = UIImage.init(named: "greenCheck.png")
}
});
}
So far it does not work as I can see in my database that test1#test.com exists.
Can somebody tell me what I missed?
EDIT
I have updated my code. I am using hasChildren and I searched for similar questions and they seem to point this direction, but I still cannot get the result I am looking for
func checkIfEmailExists(textField: UITextField) {
let ref = FIRDatabase.database().reference()
let email = firstContainerTextField.text ?? ""
ref.child("userEmails").queryEqual(toValue: email)
.observe(.value, with: { snapshot in
if !snapshot.hasChildren() {
self.firstContainerImage.image = UIImage.init(named: "redEx.png")
} else {
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
let tmp = child.value as! String
if tmp == email {
self.firstContainerImage.image = UIImage.init(named: "greenCheck.png")
}
}
}
});
}
Edit 2
I changed how I set my user up
self.ref.child("users").child((user?.uid)!).setValue(["Email": email])
so now my database looks like this
users
*****uid*****
Email: "test#test.com
As I commented earlier: you'll need to check whether the query has any results by calling snapshot.hasChildren().
func checkIfEmailExists(textField: UITextField) {
let ref = FIRDatabase.database().reference()
let email = firstContainerTextField.text ?? ""
ref.child("userEmails").queryEqual(toValue: email)
.observe(.value, with: { snapshot in
if (!snapshot.hasChildren()) {
// User doesn't exist yet...
}
});
}
The following is the structure of the Firebase function you might be looking for (Swift 4):
Auth.auth().fetchProviders(forEmail: emailAddress, completion: {
(providers, error) in
if let error = error {
print(error.localizedDescription)
} else if let providers = providers {
print(providers)
}
})
If the email address is already registered to a user, you will get a list of the providers that the email address is used for. Otherwise, the list of providers will be empty, and thus the email address is not registered.
New to contacts trying to retrieve Mobile Phone number. I have address name email but cannot figure out mobile phone. This is what I got. The portion marked with ** is where I am going wrong.
if let oldContact = self.contactItem {
let store = CNContactStore()
do {
let mykeysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactEmailAddressesKey, CNContactPostalAddressesKey,CNContactImageDataKey, CNContactImageDataAvailableKey,CNContactPhoneNumbersKey]
let contact = try store.unifiedContactWithIdentifier(oldContact.identifier, keysToFetch: mykeysToFetch)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if contact.imageDataAvailable {
if let data = contact.imageData {
self.contactImage.image = UIImage(data: data)
}
}
self.fullName.text = CNContactFormatter().stringFromContact(contact)
self.email.text = contact.emailAddresses.first?.value as? String
self.phoneNumber.text = contact.phoneNumbers.first?.value as? String
**if contact.isKeyAvailable(CNContactPhoneNumbersKey){
if let phoneNum = contact.phoneNumbers.first?.value as? String {
self.phoneNumber.text = phoneNum as String
}
}**
if contact.isKeyAvailable(CNContactPostalAddressesKey) {
if let postalAddress = contact.postalAddresses.first?.value as? CNPostalAddress {
self.address.text = CNPostalAddressFormatter().stringFromPostalAddress(postalAddress)
} else {
self.address.text = "No Address"
}
}
})
} catch {
print(error)
}
}
If you want a list of the mobile phones for a contact, you look at phoneNumbers which is an array of CNLabeledValue, and find those with a label of CNLabelPhoneNumberMobile or CNLabelPhoneNumberiPhone.
For example, you could do something like:
let mobilePhoneLabels = Set<String>(arrayLiteral: CNLabelPhoneNumberMobile, CNLabelPhoneNumberiPhone, "cell", "mobile") // use whatever you want here; you might want to include a few strings like shown here to catch any common custom permutations user may have used
let mobileNumbers = contact.phoneNumbers.filter { mobilePhoneLabels.contains($0.label) && $0.value is CNPhoneNumber }
.map { ($0.value as! CNPhoneNumber).stringValue }
So if you want the first one:
let mobileNumber = mobileNumbers.first ?? "" // or use `if let` syntax
Or if you want a string representation of the list of them:
let mobileNumberString = mobileNumbers.joinWithSeparator(" ; ")
What you do with this array of mobile numbers is up to you, but hopefully this illustrates the basic idea.