I want to get the user mail address, as shown in this thread : Getting user's default email address in Cocoa
But when I tried :
NSString *theEmailAddressWeWantToObtain = #"";
ABPerson *aPerson = [[ABAddressBook sharedAddressBook] me];
ABMultiValue *emails = [aPerson valueForProperty:kABEmailProperty];
if([emails count] > 0)
theEmailAddressWeWantToObtain = [emails valueAtIndex:0];
I have these errors :
Use of undeclared identifier 'aPerson'
Use of undeclared identifier 'ABAddressBook'
Unknown type 'ABMultiValue'
I've linked AddressBook and AddressBookUI, and imported AddressBook/AddressBook.h
What's wrong ?
These are the corrections to your code
NSString *theEmailAddressWeWantToObtain = #"";
ABPerson *aPerson = [[ABAddressBook sharedAddressBook] me];
ABMultiValueRef *emails = [aPerson valueForProperty:kABEmailProperty]; //No such thing as ABMultiValue; it's ABMultiValueRef
if(ABMultiValueGetCount(emails) > 0) //"emails" is not an array, so you can't use the "count" method
theEmailAddressWeWantToObtain = [emails valueAtIndex:0];
I'm not so familiar with Key Value Coding, so I'm not sure about your methods related to that.
This is the way I would do it
There are three email address stored in the email ABMultiValueRef: home, work, and other emails. Try this code to get the home email:
NSString *email;
ABRecordRef currentPerson = (__bridge ABRecordRef)[[PSAddressBook arrayOfContacts] objectAtIndex:identifier];
ABMultiValueRef emailsMultiValueRef = ABRecordCopyValue(currentPerson, kABPersonEmailProperty);
NSUInteger emailsCount;
//Goes through the emails to check which one is the home email
for(emailsCount = 0; emailsCount <= ABMultiValueGetCount(emailsMultiValueRef);emailsCount++){
NSString *emailLabel = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex (emailsMultiValueRef, emailsCount);
if([emailLabel isEqualToString:#"Home"]){
if ((__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emailsMultiValueRef, emailsCount) != NULL){
email = (__bridge_transfer NSString *)ABRecordCopyValue(currentPerson, kABPersonEmailProperty);
}
//If the last name property does not exist
else{
email = #"NULL";
}
}
}
CFRelease(emailsMultiValueRef);
If you have any questions about the code, just ask in the comments. Hope this helps!
EDIT:
The PSAddressBook class mentioned in the code can be found here: https://github.com/pasawaya/PSAddressBook
Related
I have a requirement to determine if a contact that is saved in the address book has multiple mobile numbers.
I have the record ID of a Contact and I need to check if that contact has multiple mobile numbers.
Is this possible?
Got the Answer!!! I have written a method to get the total count of mobile numbers for a contact
-(NSInteger)getCountOfTotalMobileNumbersForContact:(ContactData *)contactData{
NSInteger totalCountOfMobileNumbers = 0;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
ABRecordRef contact = ABAddressBookGetPersonWithRecordID(addressBook, (int)contactData.mRecordID);
if(contact != nil)
{
self.phoneNumbers = ABRecordCopyValue(contact, kABPersonPhoneProperty);
NSString *lFirstName = (__bridge_transfer NSString*)ABRecordCopyValue(contact, kABPersonFirstNameProperty);
NSString *lLastName = (__bridge_transfer NSString*)ABRecordCopyValue(contact, kABPersonLastNameProperty);
NSString *fullName = lFirstName;
if (lLastName.length) {
fullName = [[lFirstName stringByAppendingString:#" "] stringByAppendingString:lLastName];
}
totalCountOfMobileNumbers = ABMultiValueGetCount(self.phoneNumbers);
}
return totalCountOfMobileNumbers;
}
I am using the following code to retrieve different address fields from the Addressbook. It works okay for name and some properties but crashes with address. I suspect that the address is an int rather than string but can't find anything in the docs to explain why it should be different. Would appreciate any suggestions:
//This works:
CFStringRef jobtitleRef = nil;
jobtitleRef = ABRecordCopyValue(addressBookRecord, kABPersonJobTitleProperty);
NSString *jobtitle = #"";
if (jobtitleRef!=nil) {
jobtitle =[jobtitle stringByAppendingString:(__bridge NSString *)jobtitleRef];
}
//But this crashes
CFStringRef addr1Ref = nil;
addr1Ref = ABRecordCopyValue(addressBookRecord, kABPersonAddressProperty);
NSString *addr1 = #"";
if (addr1Ref!=nil) {
addr1 = [addr1 stringByAppendingString:(__bridge NSString *)addr1Ref]; //crashes on this line
}
Edit:
Found the answer in another question:
ABMultiValueRef st = ABRecordCopyValue(person, kABPersonAddressProperty);
if (ABMultiValueGetCount(st) > 0) {
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(st, 0);
self.street.text = CFDictionaryGetValue(dict, kABPersonAddressStreetKey);
}
NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
BOOL isExisted=FALSE;
for (id record in allContacts){
ABRecordRef thisContact = (__bridge ABRecordRef)record;
if(thisContact!=nil){
if (CFStringCompare(ABRecordCopyCompositeName(thisContact),
ABRecordCopyCompositeName(newPerson), 0) == kCFCompareEqualTo){
//The contact already exists!
isExisted=YES;
}
}
}
Above is my code to get the contacts and check if that contact is already exist in Addressbook but its getting an error at line if
(CFStringCompare(ABRecordCopyCompositeName(thisContact),
ABRecordCopyCompositeName(newPerson), 0) == kCFCompareEqualTo)
can anyone please help me..
am using ARC Enabled Project
Hi I had the same issue the problem is to check if your current new person hasn't any nil fields and before making comparison check if thisContact name field is not nil.
This is how i did:
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(thisContact, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(thisContact, kABPersonLastNameProperty));
you can check the phone number, email if you want to make a comparison
we're having an issue where incorrect selections are being returned from the contacts database on some devices. Is there a way to modify the below code to only return the selected item from a persons contact information? In this case we want the exact selected email address from a persons contact to be returned.
Thanks in advance for the help! Heres the code...
-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property: (ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
NSMutableDictionary *contactInfoDict = [[NSMutableDictionary alloc]
initWithObjects:#[#"", #"", #""]
forKeys:#[#"first_name", #"last_name", #"email"]];
// Use a general Core Foundation object.
CFTypeRef generalCFObject = ABRecordCopyValue(person, kABPersonFirstNameProperty);
// Get the first name.
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"first_name"];
CFRelease(generalCFObject);
}
// Get the last name.
generalCFObject = ABRecordCopyValue(person, kABPersonLastNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"last_name"];
CFRelease(generalCFObject);
}
// Load selected email addre'
if (property == kABPersonEmailProperty) {
ABMultiValueRef emails = ABRecordCopyValue(person, property);
CFIndex ix = ABMultiValueGetIndexForIdentifier(emails, identifier);
CFStringRef email = ABMultiValueCopyValueAtIndex(emails, ix);
emailAccount = (__bridge NSString *)(email);
[contactInfoDict setObject:emailAccount forKey:#"email"];
if (email) CFRelease(email);
if (emails) CFRelease(emails);
}
// init array
if (_arrContactsData == nil) {
_arrContactsData = [[NSMutableArray alloc] init];
}
// Send contact to server
[self sendContact:contactInfoDict];
// Set data for contacts
[_arrContactsData addObject:contactInfoDict];
// Reload the table view data.
[self.myTable reloadData];
// Dismiss the address book view controller.
[_addressBookController dismissViewControllerAnimated:YES completion:nil];
return NO;
}
Your code is correct.
Are the users experiencing the problem using iOS 8, by any chance? I discovered a bug in iOS 8 beta 6. If you:
Create a contact with email addresses:
Edit the contact, adding an email address and deleting one of the other email addresses:
(Note, don't just edit one of the email addresses, but rather add a new email address and remove and old one.)
In iOS 7, if you iterate through the email addresses, you will see:
{
identifier = 1;
index = 0;
label = "_$!<Work>!$_";
value = "work#gmail.com";
},
{
identifier = 2;
index = 1;
label = "_$!<Other>!$_";
value = "other#gmail.com";
}
This is correct. (When the contact was first created, the identifiers were 0 and 1, when I add the "other" email address, that gets an identifier of 2; when I delete the "home" email address, the email address with the identifier of 0 is deleted, but the other identifiers are correctly unaltered.) Thus, if you tap on the "work" email address, shouldContinueAfterSelectingPerson will return an ABMultiValueIdentifier of 1, which translates to a CFIndex of 0, which will correctly return the "work" email address.
In iOS 8 Beta 6, however, the ABMultiValueRef is incorrectly represented as:
{
identifier = 0;
index = 0;
label = "_$!<Work>!$_";
value = "work#gmail.com";
},
{
identifier = 1;
index = 1;
label = "_$!<Other>!$_";
value = "other#gmail.com";
}
These identifiers are incorrect. Worse, if you tap on the "work" email address, didSelectPerson (which replaces the deprecated shouldContinueAfterSelectingPerson) will return a ABMultiValueIdentifier of 1 (which is what it should have been ... it looks like this delegate method returns the appropriate identifier, but that the ABRecordRef for this edited record has the wrong identifiers ... not sure how they did that!), which translates to a CFIndex of 1, which will correctly return the "other" email address (!).
Worse, if you tapped on the "other" email address, didSelectPerson will return a ABMultiValueIdentifier of 2 (which is what it should have been), but if you try to retrieve the CFIndex, you'll get -1 (because no such ABMultiValueIdentifier exists) and because the app doesn't check for this, any attempt to use ABMultiValueCopyValueAtIndex with this invalid index will result in crash!
This bug seems to be fixed in the iOS8 GM seed, so it appears to be a beta problem only.
Have you ever tried to get data fields from the address book and ran into the wonderful world of ABPerson reference only to find it reads like the blueprints to a space rocket?
I've gotten so far but I still need help getting just the Twitter username key & value:
//I tried this but I can't seem to get the if statement to work
ABMutableMultiValueRef socialMulti = ABRecordCopyValue(person, kABPersonSocialProfileProperty);
NSMutableDictionary *mySocialDict = [NSMutableDictionary dictionaryWithCapacity:ABMultiValueGetCount(socialMulti)];
NSLog(#"entering social dict of count %ld", ABMultiValueGetCount(socialMulti));
for (CFIndex i = 0; i < ABMultiValueGetCount(socialMulti); i++) {
CFStringRef socialLabel = ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(socialMulti, i));
CFStringRef social = ABMultiValueCopyValueAtIndex(socialMulti, i);
if ([(__bridge NSString*)socialLabel isEqualToString:#"twitter"]) {
NSLog(#"we got a twitter");
}
[mySocialDict setObject:(__bridge NSString*)social forKey:(__bridge NSString*)socialLabel];
NSLog(#"social is %#",social);
CFRelease(social);
CFRelease(socialLabel);
}
I'm actually just interested in the twitter username. I know I could get it from the dictionary I created but I want to get it directly. I plan to eliminate the NSDictionary step anyway.
Here's an excerpt from my code. Replace your var names as necessary.
ABMultiValueRef socialMulti = ABRecordCopyValue(recordRef, kABPersonSocialProfileProperty);
NSMutableArray* twitterHandlesArray = [[NSMutableArray alloc] initWithCapacity:ABMultiValueGetCount(socialMulti)];
for (CFIndex i = 0; i < ABMultiValueGetCount(socialMulti); i++) {
NSDictionary* social = (__bridge NSDictionary*)ABMultiValueCopyValueAtIndex(socialMulti, i);
if ([social[#"service"] isEqualToString:(__bridge NSString*)kABPersonSocialProfileServiceTwitter]) {
NSString* username = (NSString*)social[#"username"];
NSLog(#"we got a twitter. username is %#", username);
[twitterHandlesArray addObject:[[username conditionedAsTwitterHandle] SHA2Digest]];
}
}