ABRecordCopyValue different values? - ios

Im trying to search within my contact list, but this codes crashes if it's executed freshly from the app store, or, as Im testing now, from TestFlight.
If I uninstall the app and hit Run it goes perfectly. But executed right from TestFlight it crashes, the crash log states and it fails in the line where i
BOOL found = NO;
NSString *name;
int i = 0;
NSLog(#"Hay %i", [people count]);
while (!found && i < [people count]) {
ABRecordRef person = (ABRecordRef)[people objectAtIndex:i];
ABMultiValueRef multi = ABRecordCopyValue(person, kABPersonPhoneProperty);
NSLog(#"address: %#", multi);
//Freshly from TestFlight this prints "address: Denis" wich is a contac, executed from Xcode it prints, address: ABMultiValueRef 0x1fb68400 with 1 value(s), so I see here's the problem
if([[(NSMutableString*)ABMultiValueCopyValueAtIndex(multi, 0) componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:#""]){
NSMutableString *tempPhone = [[NSMutableString alloc]initWithString:[[(NSMutableString*)ABMultiValueCopyValueAtIndex(multi, 0) componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:#""]];
NSLog(#"telf: %#", tempPhone);
int length = [tempPhone length] - 9;
NSString *tempPhone2;
if(length >= 0){
tempPhone2 = [[NSString alloc]initWithString:[tempPhone substringFromIndex:length]];
}
NSLog(#"el telf: %# y nombre %# int %i",tempPhone2, [NSString stringWithFormat:#"%# %#",ABRecordCopyValue(person, kABPersonFirstNameProperty) ? (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty) : #"",ABRecordCopyValue(person, kABPersonLastNameProperty) ? (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty) : #""], i);
if([[key objectForKey:#"phone"] isEqualToString:tempPhone2]){
name = [NSString stringWithFormat:#"%# %#",ABRecordCopyValue(person, kABPersonFirstNameProperty) ? (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty) : #"",ABRecordCopyValue(person, kABPersonLastNameProperty) ? (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty) : #""];
found = YES;
}
}
i++;
}
On this line NSLog(#"address: %#", multi); it prints when its Fresh from TestFlight "address: Denis" wich is a contact, executed from Xcode it prints, "address: ABMultiValueRef 0x1fb68400 with 1 value(s)...", so I see here's the problem, that difference, what I dont understand is why is different, can you tell me why?

It seems that you are not accessing the address book data correctly. I understand, the right way would be something like:
ABMultiValueRef multi = ABRecordCopyValue(person, kABPersonPhoneProperty);
NSString* label;
for (int i = 0; i < ABMultiValueGetCount(multi); i++) {
label = (NSString*)ABMultiValueCopyLabelAtIndex(multi, i);
... <DO YOUR PROCESSING on label>
}
Hope this helps.

Related

How to implement number comparison like in the native iPhone contacts app?

I want to compare two numbers, like in case, for e.g. the number is 987654.
It can be saved as +91 987654 or 0987654. But while searching or comparing, the number exactly matches and shows properly.
Right now I am using this code to compare the exact number. How do I enhance it?
// Remove non numeric characters from the phone number
phoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]] componentsJoinedByString:#""];
NSPredicate *predicate = [NSPredicate predicateWithBlock: ^(id record, NSDictionary *bindings) {
ABMultiValueRef phoneNumbers = ABRecordCopyValue( (__bridge ABRecordRef)record, kABPersonPhoneProperty);
BOOL result = NO;
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
NSString *contactPhoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);
contactPhoneNumber = [[contactPhoneNumber componentsSeparatedByCharactersInSet: [[NSCharacterSet alphanumericCharacterSet] invertedSet]] componentsJoinedByString:#""];
//Comparing the string are equal. phoneNumber is the number I am comparing to.
if ([contactPhoneNumber isEqualToString:phoneNumber]) {
result = YES;
break;
}
}
CFRelease(phoneNumbers);
return result;
}];
The above code results YES, only if the contactPhoneNumber and phoneNumber are exactly same.
Not when 0987654 or +91 987654 with 987654.
The same thing works in WhatsApp number comparison too.
Can anyone give any leads?
Alright, I know that this isn't the neatest code, but...
NSString *originalPhoneNumber = [insert phone String];
int phoneNumber = [originalPhoneNumber intValue];
NSString *phoneFormatOne;//This will be your number formatted like 0987654
NSString *phoneFormatTwo;//This will be your number formatted like +91 987654
int phoneNumberFormatOne = [phoneFormatOne intValue];
NSString *partOne = [phoneFormatTwo substringWithRange:NSMakeRange(1,3)];
NSString *partTwo = [phoneFormatTwo substringWithRange:NSMakeRange(4,10)];
int phoneNumberFormatTwo = [partOne intValue]*1000000 + [partTwo intValue];
Now you have all three in integer format, called phoneNumber, phoneNumberFormatOne, and phoneNumberFormatTwo. You can now just compare integers with an == in a if statement.

iOS - [stringObject class] returns "(null)" from phone contacts? How is this possible?

So I have let's say:
NSString *stringObject = (__bridge NSString*)ABRecordCopyValue(contactPerson, kABPersonLastNameProperty);
NSLog(#"%#", [stringObject class]); - RETURNS "(null)"
How is this even possible? And how do you work around something like this?
I am trying to return an empty string in case that string is "(null)".
I've tried:
NSString *lastName = ![stringObject isEqual:#"(null)"] ? stringObject : [NSString string];
OR
NSString *lastName = ![stringObject isEqualToString:#"(null)"] ? stringObject : [NSString string];
OR
NSString *lastName = ![stringObject isEqual:[NSNull null]] ? stringObject : [NSString string];
OR
NSString *lastName = [stringObject isKindOfClass:[NSString class]] ? [NSString string] : stringObject ;
OR
NSString *lastName = (stringObject == nil) ? [NSString string] : stringObject ;
Has anyone other suggestions?
Thank you in advance.
This contact has no last name, and therefore stringObject is nil. Verify with some code:
NSLog(#"Last name='%#'", stringObject);
EDIT How to verify:
Simply test if the object is nil and better still check if the string has length > 0, which you can do as simply as:
NSString *stringObject = (__bridge NSString*)ABRecordCopyValue(contactPerson, kABPersonLastNameProperty);
if ([stringObject length]) {
NSLog(#"Contact last name = '%#'", stringObject);
} else {
NSLog(#"Contact has no last name; they must play for Brazil");
}
You can try this
NSString *lastName = [stringObject isKindOfClass:[NSNull class]] ? [NSString string] : stringObject ;

Split NSString from first whitespace

I have a name textfield in my app, where both the firstname maybe a middle and a lastname is written. Now I want to split these components by the first whitespace, the space between the firstname and the middlename/lastname, so I can put it into my model.
For example:
Textfield Text: John D. Sowers
String 1: John
String 2: D. Sowers.
I have tried using [[self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] firstObject]; & [[self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] lastObject];
But these only work if have a name without a middlename. Since it gets the first and the last object, and the middlename is ignored.
So how would I manage to accomplish what I want?
/*fullNameString is an NSString*/
NSRange rangeOfSpace = [fullNameString rangeOfString:#" "];
NSString *first = rangeOfSpace.location == NSNotFound ? fullNameString : [fullNameString substringToIndex:rangeOfSpace.location];
NSString *last = rangeOfSpace.location == NSNotFound ? nil :[fullNameString substringFromIndex:rangeOfSpace.location + 1];
...the conditional assignment (rangeOfSpace.location == NSNotFound ? <<default value>> : <<real first/last name>>) protects against an index out of bounds error.
Well that method is giving you an array with all the words split by white space, so then you can grab the first object as the first name and the rest of the objects as middle/last/etc
NSArray *ar = [self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *firstName = [ar firstObject];
NSMutableString *rest = [[NSMutableString alloc] init];
for(int i = 1; i < ar.count; i++)
{
[rest appendString:[ar objectAtIndex:i]];
[rest appendString:#" "];
}
//now first name has the first name
//rest has the rest
There might be easier way to do this, but this is one way..
Hope it helps
Daniel
I think this example below I did, solves your problem.
Remember you can assign values from the array directly, without transforming into string.
Here is an example:
NSString *textField = #"John D. Sowers";
NSArray *fullName = [textField componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" "]];
if (fullName.count)
{
if (fullName.count > 2)
{
NSLog(#"Array has more than 2 objects");
NSString *name = fullName[0];
NSLog(#"Name:%#",name);
NSString *middleName = fullName[1];
NSLog(#"Middle Name:%#",middleName);
NSString *lastName = fullName[2];
NSLog(#"Last Name:%#",lastName);
}
else if(fullName.count == 2)
{
NSLog(#"Array has 2 objects");
NSString *name = fullName[0];
NSLog(#"Name:%#",name);
NSString *lastName = fullName[1];
NSLog(#"Last Name:%#",lastName);
}
else
{
NSString *name = fullName[0];
}
}
I found this to be most robust:
NSString *fullNameString = #"\n Barnaby Marmaduke \n \n Aloysius ";
NSMutableArray *nameArray = [[fullNameString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy];
[nameArray removeObject:#""];
NSString *firstName = [nameArray firstObject];
if(nameArray.count)
{
[nameArray removeObjectAtIndex:0];
}
NSString *nameRemainder = [nameArray componentsJoinedByString:#" "];
Bob's your uncle.

Error getting information from address book

I'm having an issue retrieving an array of certain data from the address book. Here's the code:
- (void) getContacts{
ABAddressBookRef ab = ABAddressBookCreate();
NSMutableArray *retVal = (__bridge NSMutableArray *)(ABAddressBookCopyArrayOfAllPeople(ab));
CFRelease(ab);
contact* temp=[[contact alloc] init];
NSMutableArray* tempArray=[[NSMutableArray alloc]init];
for(int i=0;i<[retVal count];i++)
[tempArray insertObject:
[NSString stringWithFormat:#"%#",
[temp set2:[NSString stringWithFormat:#"%#",
[[retVal objectAtIndex:i] kABPersonFirstNameProperty]]
last:[NSString stringWithFormat:#"%#",
[[retVal objectAtIndex:i] kABPersonLastNameProperty]]
number:[NSString stringWithFormat:#"%#",
[[retVal objectAtIndex:i] kABPersonPhoneProperty]]]] atIndex:i];
_objects=tempArray;
[self alert:[NSString stringWithFormat:#"%#",_objects] title:#"TEMP"];
}
The errors I'm getting are about the kABPerson properties.
Some more clarification: essentially I'm grabbing all the data from the address book into the first array and then I'm manually going through that array and attempting to retrieve the data that I need for the rest of my app.
Any ideas?
Just for more clarification here's my contact.h file:
#interface contact : NSString{
NSString* first;
NSString* last;
NSString* number;
}
#end
And here's my contact.m file:
#implementation contact
- (void) set:(NSString*)first2 last:(NSString*)last2 number:(NSString*)number2{
first=first2;
last=last2;
number=number2;
}
- (contact*) set2:(NSString*)first2 last:(NSString*)last2 number:(NSString*)number2{
first=first2;
last=last2;
number=number2;
return self;
}
#end
Here's that line that seems to be too long to post:
//Enter contact into tempArray
[tempArray insertObject:[NSString stringWithFormat:#"%#",[temp set:[NSString stringWithFormat:#"%#",(__bridge NSString *)(ABRecordCopyValue((__bridge ABMultiValueRef)[retVal objectAtIndex:i],kABPersonFirstNameProperty))] last:[NSString stringWithFormat:#"%#",(__bridge NSString *)(ABRecordCopyValue((__bridge ABMultiValueRef)[retVal objectAtIndex:i],kABPersonLastNameProperty))] number:(__bridge NSString *)ABMultiValueCopyValueAtIndex((__bridge ABMultiValueRef)((__bridge NSString*)ABRecordCopyValue((__bridge ABRecordRef)([retVal objectAtIndex:i]),kABPersonPhoneProperty)), 0)]] atIndex:i];
kABPersonFirstNameProperty is a property ID, not an Objective-C object property.
That is, you can't use [[retVal objectAtIndex:i] kABPersonFirstNameProperty] -- you will instead need to access the first and last names like this:
CFStringRef firstName = ABRecordCopyValue ([retVal objectAtIndex:i], kABPersonFirstNameProperty);
CFStringRef lastName = ABRecordCopyValue ([retVal objectAtIndex:i], kABPersonLastNameProperty);
CFStringRef phoneNum = ABRecordCopyValue ([retVal objectAtIndex:i], kABPersonPhoneProperty);
Then don't forget that ABRecordCopyValue follows the Create Rule -- you'll need to CFRelease(firstName) afterwards.

NSLinguisticTagger Memory Leak

I've been fiddling in Xcode 4.2 with iOS 5.0's new NSLinguisticTagger. My objective with this function is to take in an address book record and then spit out a composite name as an NSString, sort of like what ABRecordCopyCompositeName does, but taking into account naming order for East Asian languages and Hungarian (last first instead of first last). Here's the function:
NSString *text = [self getLocalizedFullNameOfRecord:[contacts objectAtIndex:indexPath.section];
- (NSString *) getLocalizedFullNameOfRecord:(ABRecordRef) person
{
NSString *firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *middleName = ABRecordCopyValue(person, kABPersonMiddleNameProperty);
NSString *lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
NSString *prefix = ABRecordCopyValue(person, kABPersonPrefixProperty);
NSString *suffix = ABRecordCopyValue(person, kABPersonSuffixProperty);
NSString *fullName = #"";
__block BOOL Asian;
// Apologies to all Hungarians who aren't actually Asian
__block NSArray *asianLanguages = [NSArray arrayWithObjects:#"zh-Hant", #"zh-Hans", #"ja", #"ko", #"hu", #"vi", nil];
[firstName enumerateLinguisticTagsInRange:NSMakeRange(0, firstName.length) scheme: NSLinguisticTagSchemeLanguage options: NSLinguisticTaggerOmitWhitespace orthography: nil usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop){
if ([asianLanguages containsObject:tag])
Asian = YES;
else
Asian = NO;
}];
if(prefix)
fullName = [fullName stringByAppendingFormat:#"%# ", prefix];
if(Asian && lastName)
fullName = [fullName stringByAppendingFormat:#"%# ", lastName];
else if(firstName)
fullName = [fullName stringByAppendingFormat:#"%# ", firstName];
if(middleName)
fullName = [fullName stringByAppendingFormat:#"%# ", middleName];
if(Asian && firstName)
fullName = [fullName stringByAppendingFormat:#"%# ", firstName];
else if(lastName)
fullName = [fullName stringByAppendingFormat:#"%# ", lastName];
if(suffix)
fullName = [fullName stringByAppendingFormat:#"%#", suffix];
[firstName release];
[middleName release];
[lastName release];
[prefix release];
[suffix release];
return fullName;
}
Instruments tells me that I am leaking some 16 to 32 bytes with every iteration of this function, on the enumerateLinguisticTagger (and not the blocks part, apparently). Since online resources for NSLinguisticTagger is limited to its class reference and a single tutorial, I have no idea where and how to start looking for the leak.
Help please?
I had the same problem. In my case, leaks occurred when string has line breaks (\n or \r).

Resources