I've caught an error:
Fatal Exception: NSRangeException
*** -[__NSArrayI objectAtIndex:]: index 1330 beyond bounds [0 .. 1329]
At string
NSArray *currentABRecords = [ApplicationPhoneDirectory records];
ApplicationPhoneDirectory is NSObject with unique contacts (dict and array).
But I think the error is about working with memory, how can I manage it more properly to avoid appearance of such a problem?
Or, in case if I'm incorrect I can put records part in there.
upd:
static NSArray *RecordsForABInterval(UInt32 start, UInt32 end, CFArrayRef allPeople) {
NSMutableArray *peoples = [NSMutableArray arrayWithCapacity:(end - start) * 2];
for (int i = (int) start; i < end; i++) {
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
NSString *firstName = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSString *fullName = [NSString stringWithFormat:#"%# %#",
firstName.length > 0 ? firstName : #"",
lastName.length > 0 ? lastName : #""];
fullName = [fullName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
ABMutableMultiValueRef phoneList = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex phonesCount = ABMultiValueGetCount(phoneList);
for (int j = 0; j < phonesCount; ++j) {
CFTypeRef ABphone = ABMultiValueCopyValueAtIndex(phoneList, j);
NSString *phone = (NSString *)CFBridgingRelease(ABphone);
NSString *phoneInSMFormat = [phone phoneNumberInSMFormat];
if ([phoneInSMFormat isValidSMPhoneNumber]) {
NSDictionary *record = #{
#"name" : fullName,
#"phone" : phoneInSMFormat,
#"original" : phone
};
[peoples addObject:record];
}
}
if (phoneList != NULL) {
CFRelease(phoneList);
}
}
return peoples;
}
+ (NSArray *)records {
const int MaxAutoreleaseStep = 500;
NSMutableArray *records = [NSMutableArray array];
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
__block BOOL accessGranted = NO;
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
dispatch_async(dispatch_get_main_queue(), ^{
accessGranted = granted;
});
});
} else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add the contact
accessGranted = YES;
}
else {
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
if (addressBook != NULL) {
CFRelease(addressBook);
}
return nil;
}
// TODO: review this logic - should it be a single call to AB?
if (addressBook != NULL) {
CFRelease(addressBook);
}
if (accessGranted) {
ABAddressBookRef addressbook = ABAddressBookCreateWithOptions(NULL, &error);
if (error != NULL) {
if (addressbook != NULL) {
CFRelease(addressbook);
}
return nil;
}
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressbook);
CFIndex peopleCount = ABAddressBookGetPersonCount(addressbook);
for (int start = 0; start < peopleCount; start += MaxAutoreleaseStep) {
#autoreleasepool {
int end = start + MaxAutoreleaseStep;
NSArray *contactListCut = RecordsForABInterval((UInt32) start, (UInt32) MIN((int)peopleCount, end), allPeople);
[records addObjectsFromArray:contactListCut];
}
}
if (allPeople != NULL) {
CFRelease(allPeople);
}
if (addressbook != NULL) {
CFRelease(addressbook);
}
}
return records;
}
upd2:
- (NSString *)phoneNumberInSMFormat {
NSString *phone = [self numericPresentation];
if (phone.length > 0 && [phone characterAtIndex:0] == '8') {
NSMutableString *modifiedString = [phone mutableCopy];
[modifiedString replaceCharactersInRange:NSMakeRange(0, 1) withString:#"7"];
phone = modifiedString;
}
return phone;
}
- (BOOL)isValidSMPhoneNumber {
static NSCharacterSet *characterSet = nil;
if (characterSet == nil) {
characterSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
}
if ([self rangeOfCharacterFromSet:characterSet].location != NSNotFound) {
return NO;
}
if (self.length < 7 || self.length > 12) {
return NO;
}
return [self characterAtIndex:0] != '8';
}
Related
How to find a single number from ABAdressBook which contains 10 000 contacts?
Currently I am using ABAddressBookRef. Is there an alternative method to reduce iterating?
My code snippet:
if([numberType intValue] == NUMBER_TYPE_EXTERNAL && [appDelegate isNativeContactAccess] == YES)
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(numberType == %#)",[NSNumber numberWithInt:NUMBER_TYPE_EXTERNAL]];
[fetchRequest setPredicate:predicate];
NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
/* The method ABAddressBookCreate() is deprecated in ios 6 so below method is used here */
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
for (NSInteger resultCnt=0; resultCnt<[results count]; resultCnt++)
{
Contact *contact = [results objectAtIndex:resultCnt];
ABRecordID r = [contact.indexValue intValue];
ABRecordRef fetchData = ABAddressBookGetPersonWithRecordID(addressBook, r);
if(fetchData != nil)
{
NSUInteger lengthOfSearchStr = [searchNumber length];
ABMultiValueRef multi = ABRecordCopyValue(fetchData, kABPersonPhoneProperty);
NSUInteger j=0;
for(j=0; j<ABMultiValueGetCount(multi); j++)
{
NSString *getNum = (NSString *)ABMultiValueCopyValueAtIndex(multi, j);
NSString *removedspecialchar6 = [getNum stringByReplacingOccurrencesOfString:#"[^0-9*+#]" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0,[getNum length])];
if(lengthOfSearchStr <= [removedspecialchar6 length])
{
number = [removedspecialchar6 substringFromIndex:[removedspecialchar6 length] - lengthOfSearchStr];
if([number isEqualToString:searchNumber])
{
[getNum release];
CFRelease(addressBook);
CFRelease(multi);
return contact;
}
}
[getNum release];
}
CFRelease(multi);
}
}
CFRelease(addressBook);
}
NSUInteger index;
NSUInteger findIndex;
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *constactsNo = (NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
if ( constactsNo ==nil )
{
CFRelease(addressBook);
return;
}
for ( index=0; index<[constactsNo count]; index++ )
{
ABRecordRef find = (ABRecordRef)[constactsNo objectAtIndex:index];
ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(find, kABPersonPhoneProperty);
CFIndex phoneNumberCount = ABMultiValueGetCount( phoneNumbers );
for ( findIndex =0; findIndex <phoneNumberCount; findIndex ++ )
{
CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNumbers, findIndex );
CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNumbers, findIndex );
CFStringRef phoneNumberLocalizedLabel = ABAddressBookCopyLocalizedLabel( phoneNumberLabel );
CFRelease(phoneNumberLocalizedLabel);
CFRelease(phoneNumberLabel);
CFRelease(phoneNumberValue);
}
}
[constactsNo release];
CFRelease(addressBook);
i use linphone SDK in my application. When i start to run app crash happening immediately.
After app start it's call [Fastaddreesbook init] which called [FastAddreesBook reload] which called [FastAddreesBook loadData] which called [FastAddreesBook normalizeSipURI] and exc_bad_access Crash happen in this method:
LinphoneAddress* linphoneAddress = linphone_core_interpret_url([LinphoneManager getLc], [address UTF8String]);
Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
/* FastAddressBook.h
*
* Copyright (C) 2011 Belledonne Comunications, Grenoble, France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef __IPHONE_9_0
#import <Contacts/Contacts.h>
#endif
#import "FastAddressBook.h"
#import "LinphoneManager.h"
#import "BundleLocalData.h"
#import "AppUtil.h"
#import "WebserviceUtil.h"
#import "ContactEntry.h"
#import "ContactsViewController.h"
#implementation FastAddressBook
static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void *context);
+ (NSString*)getContactDisplayName:(ABRecordRef)contact {
NSString *retString = nil;
if (contact) {
CFStringRef lDisplayName = ABRecordCopyCompositeName(contact);
if(lDisplayName != NULL) {
retString = [NSString stringWithString:(NSString*)lDisplayName];
CFRelease(lDisplayName);
}
}
return retString;
}
+ (UIImage*)squareImageCrop:(UIImage*)image
{
UIImage *ret = nil;
// This calculates the crop area.
float originalWidth = image.size.width;
float originalHeight = image.size.height;
float edge = fminf(originalWidth, originalHeight);
float posX = (originalWidth - edge) / 2.0f;
float posY = (originalHeight - edge) / 2.0f;
CGRect cropSquare = CGRectMake(posX, posY,
edge, edge);
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, cropSquare);
ret = [UIImage imageWithCGImage:imageRef
scale:image.scale
orientation:image.imageOrientation];
CGImageRelease(imageRef);
return ret;
}
+ (UIImage*)getContactImage:(ABRecordRef)contact thumbnail:(BOOL)thumbnail {
UIImage* retImage = nil;
if (contact && ABPersonHasImageData(contact)) {
CFDataRef imgData = ABPersonCopyImageDataWithFormat(contact, thumbnail?
kABPersonImageFormatThumbnail: kABPersonImageFormatOriginalSize);
retImage = [UIImage imageWithData:(NSData *)imgData];
if(imgData != NULL) {
CFRelease(imgData);
}
if (retImage != nil && retImage.size.width != retImage.size.height) {
[LinphoneLogger log:LinphoneLoggerLog format:#"Image is not square : cropping it."];
return [self squareImageCrop:retImage];
}
}
return retImage;
}
- (ABRecordRef)getContact:(NSString*)address {
#synchronized (addressBookMap){
return (ABRecordRef)addressBookMap[address];
}
}
+ (BOOL)isSipURI:(NSString*)address {
return [address hasPrefix:#"sip:"] || [address hasPrefix:#"sips:"];
}
+ (NSString*)appendCountryCodeIfPossible:(NSString*)number {
if (![number hasPrefix:#"+"] && ![number hasPrefix:#"00"]) {
NSString* lCountryCode = [[LinphoneManager instance] lpConfigStringForKey:#"countrycode_preference"];
if (lCountryCode && lCountryCode.length>0) {
//append country code
return [lCountryCode stringByAppendingString:number];
}
}
return number;
}
+ (NSString*)normalizeSipURI:(NSString*)address {
NSString *normalizedSipAddress = nil;
LinphoneAddress* linphoneAddress = linphone_core_interpret_url([LinphoneManager getLc], [address UTF8String]);
if(linphoneAddress != NULL) {
char *tmp = linphone_address_as_string_uri_only(linphoneAddress);
if(tmp != NULL) {
normalizedSipAddress = [NSString stringWithUTF8String:tmp];
ms_free(tmp);
}
linphone_address_destroy(linphoneAddress);
}
return normalizedSipAddress;
}
+ (NSString*)normalizePhoneNumber:(NSString*)address {
NSMutableString* lNormalizedAddress = [NSMutableString stringWithString:address];
[lNormalizedAddress replaceOccurrencesOfString:#" "
withString:#""
options:0
range:NSMakeRange(0, lNormalizedAddress.length)];
[lNormalizedAddress replaceOccurrencesOfString:#"("
withString:#""
options:0
range:NSMakeRange(0, lNormalizedAddress.length)];
[lNormalizedAddress replaceOccurrencesOfString:#")"
withString:#""
options:0
range:NSMakeRange(0, lNormalizedAddress.length)];
[lNormalizedAddress replaceOccurrencesOfString:#"-"
withString:#""
options:0
range:NSMakeRange(0, lNormalizedAddress.length)];
return [FastAddressBook appendCountryCodeIfPossible:lNormalizedAddress];
}
+ (BOOL)isAuthorized {
//addme // return !ABAddressBookGetAuthorizationStatus || ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized;
return ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized;
}
- (FastAddressBook*)init {
if ((self = [super init]) != nil) {
addressBookMap = [[NSMutableDictionary alloc] init];
addressBook = nil;
[self reload];
}
self.needToUpdate = FALSE;
if ([CNContactStore class]) {
//ios9 or later
CNEntityType entityType = CNEntityTypeContacts;
if([CNContactStore authorizationStatusForEntityType:entityType] == CNAuthorizationStatusNotDetermined) {
CNContactStore * contactStore = [[CNContactStore alloc] init];
// nslo(#"CNContactStore requesting authorization");
[contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) {
// LOGD(#"CNContactStore authorization granted");
}];
} else if([CNContactStore authorizationStatusForEntityType:entityType]== CNAuthorizationStatusAuthorized) {
// LOGD(#"CNContactStore authorization granted");
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateAddressBook:) name:CNContactStoreDidChangeNotification object:nil];
}
return self;
}
-(void) updateAddressBook:(NSNotification*) notif {
// LOGD(#"address book has changed");
self.needToUpdate = TRUE;
}
- (void) checkContactListForJogvoiceList {
// if (![BundleLocalData isLoadingJogvoiceContactList]) {
// [BundleLocalData setLoadingJogvoiceContactList:true];
int maxPhoneNumberSubmit = 200;
NSArray *lContacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
NSMutableDictionary *phoneNumberContactsDictionary = [[NSMutableDictionary alloc] init];
NSMutableArray *allPhoneNumberList = [[NSMutableArray alloc] init];
for (id lPerson in lContacts) {
ABRecordRef person = (ABRecordRef)lPerson;
NSArray *phoneList = [AppUtil getContactPhoneList:person];
for (NSString* phoneNumber in phoneList) {
NSMutableArray* contactList = phoneNumberContactsDictionary[phoneNumber];
if (!contactList) {
contactList = [[NSMutableArray alloc] init];
}
[contactList addObject:(__bridge ABRecordRef)person];
phoneNumberContactsDictionary[phoneNumber] = contactList;
}
[allPhoneNumberList addObjectsFromArray:phoneList];
if (allPhoneNumberList.count >= maxPhoneNumberSubmit) {
[self checkContactList:allPhoneNumberList phoneNumberContactsDictionary:phoneNumberContactsDictionary];
}
}
if (allPhoneNumberList.count > 0) {
[self checkContactList:allPhoneNumberList phoneNumberContactsDictionary:phoneNumberContactsDictionary];
}
// ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self);
// [BundleLocalData setLoadingJogvoiceContactList:false];
// }
}
-(void) checkContactList:(NSMutableArray*)allPhoneNumberList phoneNumberContactsDictionary:(NSMutableDictionary*)phoneNumberContactsDictionary {
[WebserviceUtil apiGetUsersRegistered:[NSArray arrayWithArray:allPhoneNumberList]
success:^(AFHTTPRequestOperation *operation, id responseObject){
NSDictionary* response = responseObject;
for (id phoneNumber in allPhoneNumberList) {
NSNumber *status = response[phoneNumber];
if (status.intValue == 1) { // registered
NSArray* contactList = phoneNumberContactsDictionary[phoneNumber];
for (int index = 0; index < contactList.count; index++) {
ABRecordRef contact = (__bridge ABRecordRef) contactList[index];
[self saveContact:phoneNumber contact:contact];
}
}
}
[self saveAddressBook];
[allPhoneNumberList removeAllObjects];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// nothing
}];
}
-(void) saveContact:(NSString*)phoneNumber contact:(ABRecordRef)contact {
if(contact == NULL || phoneNumber == NULL) {
return;
}
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
if (!lMap) {
return;
}
BOOL avafoneAlready = false;
for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(lMap, i);
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i);
if(CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
if(CFStringCompare((CFStringRef)[LinphoneManager instance].contactSipField, CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), kCFCompareCaseInsensitive) == 0) {
avafoneAlready = true;
}
} else {
//check domain
LinphoneAddress* address = linphone_address_new(((NSString*)CFDictionaryGetValue(lDict,kABPersonInstantMessageUsernameKey)).UTF8String);
if (address) {
if ([[ContactSelection getSipFilter] compare:#"*" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
avafoneAlready = true;
} else {
NSString* domain = [NSString stringWithCString:linphone_address_get_domain(address)
encoding:[NSString defaultCStringEncoding]];
if ([domain compare:[ContactSelection getSipFilter] options:NSCaseInsensitiveSearch] == NSOrderedSame) {
avafoneAlready = true;
}
}
linphone_address_destroy(address);
}
}
CFRelease(lDict);
if(avafoneAlready) {
avafoneAlready = true;
break;
}
}
CFRelease(lMap);
if (avafoneAlready) {
return;
}
NSString *value = [NSString stringWithFormat:#"900%#", phoneNumber];
ContactEntry *entry = nil;
ABMultiValueRef lcMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
if(lcMap != NULL) {
lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
} else {
lMap = ABMultiValueCreateMutable(kABStringPropertyType);
}
ABMultiValueIdentifier index;
NSError* error = NULL;
CFStringRef keys[] = { kABPersonInstantMessageUsernameKey, kABPersonInstantMessageServiceKey};
CFTypeRef values[] = { [value copy], [LinphoneManager instance].contactSipField };
CFDictionaryRef lDict = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, NULL, NULL);
if (entry) {
index = ABMultiValueGetIndexForIdentifier(lMap, entry.identifier);
ABMultiValueReplaceValueAtIndex(lMap, lDict, index);
} else {
CFStringRef label = (CFStringRef)[NSString stringWithString:(NSString*)kABPersonPhoneMobileLabel];
ABMultiValueAddValueAndLabel(lMap, lDict, label, &index);
}
if (!ABRecordSetValue(contact, kABPersonInstantMessageProperty, lMap, (CFErrorRef*)&error)) {
[LinphoneLogger log:LinphoneLoggerLog format:#"Can't set contact with value [%#] cause [%#]", value,error.localizedDescription];
CFRelease(lMap);
} else {
if (entry == nil) {
entry = [[[ContactEntry alloc] initWithData:index] autorelease];
}
CFRelease(lDict);
CFRelease(lMap);
/*check if message type is kept or not*/
lcMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
index = ABMultiValueGetIndexForIdentifier(lMap, entry.identifier);
lDict = ABMultiValueCopyValueAtIndex(lMap,index);
// if(!CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
/*too bad probably a gtalk number, storing uri*/
NSString* username = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
LinphoneAddress* address = linphone_core_interpret_url([LinphoneManager getLc]
,username.UTF8String);
if(address){
char* uri = linphone_address_as_string_uri_only(address);
CFStringRef keys[] = { kABPersonInstantMessageUsernameKey, kABPersonInstantMessageServiceKey};
CFTypeRef values[] = { [NSString stringWithCString:uri encoding:[NSString defaultCStringEncoding]], [LinphoneManager instance].contactSipField };
CFDictionaryRef lDict2 = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, NULL, NULL);
ABMultiValueReplaceValueAtIndex(lMap, lDict2, index);
if (!ABRecordSetValue(contact, kABPersonInstantMessageProperty, lMap, (CFErrorRef*)&error)) {
[LinphoneLogger log:LinphoneLoggerLog format:#"Can't set contact with value [%#] cause [%#]", value,error.localizedDescription];
}
CFRelease(lDict2);
linphone_address_destroy(address);
ms_free(uri);
}
// }
CFDictionaryRef lDict = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, NULL, NULL);
ABMultiValueReplaceValueAtIndex(lMap, lDict, index);
CFRelease(lMap);
}
CFRelease(lDict);
}
- (void)saveAddressBook {
if( addressBook != nil ){
NSError* err = nil;
if( !ABAddressBookSave(addressBook, (CFErrorRef*)err) ){
Linphone_warn(#"Couldn't save Address Book");
}
}
}
- (void)reload {
NSLog(#"Fastadd reload first is loaded");
CFErrorRef error;
// create if it doesn't exist
if (addressBook == nil) {
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
}
if (addressBook != nil) {
__weak FastAddressBook *weakSelf = self;
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (!granted) {
Linphone_warn(#"Permission for address book acces was denied: %#", [(__bridge NSError *)error description]);
return;
}
ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(weakSelf));
dispatch_async(dispatch_get_main_queue(), ^(void) {
[weakSelf loadData];
});
});
} else {
Linphone_warn(#"Create AddressBook failed, reason: %#", [(__bridge NSError *)error localizedDescription]);
}
/*
//method1
if(addressBook != nil) {
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self);
CFRelease(addressBook);
addressBook = nil;
}
NSError *error = nil;
addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
if(addressBook != NULL) {
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
ABAddressBookRegisterExternalChangeCallback (addressBook, sync_address_book, self);
[self loadData];
});
} else {
[LinphoneLogger log:LinphoneLoggerError format:#"Create AddressBook: Fail(%#)", [error localizedDescription]];
}
*/
}
- (void)loadData {
ABAddressBookRevert(addressBook);
#synchronized (addressBookMap) {
[addressBookMap removeAllObjects];
//melog
NSLog(#"Fastadd loaddata is loaded");
NSArray *lContacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
for (id lPerson in lContacts) {
// Phone
{
ABMultiValueRef lMap = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonPhoneProperty);
if(lMap) {
for (int i=0; i<ABMultiValueGetCount(lMap); i++) {
CFStringRef lValue = ABMultiValueCopyValueAtIndex(lMap, i);
CFStringRef lLabel = ABMultiValueCopyLabelAtIndex(lMap, i);
CFStringRef lLocalizedLabel = ABAddressBookCopyLocalizedLabel(lLabel);
NSString* lNormalizedKey = [FastAddressBook normalizePhoneNumber:(NSString*)lValue];
NSString* lNormalizedSipKey = [FastAddressBook normalizeSipURI:lNormalizedKey];
if (lNormalizedSipKey != NULL) lNormalizedKey = lNormalizedSipKey;
addressBookMap[lNormalizedKey] = lPerson;
CFRelease(lValue);
if (lLabel) CFRelease(lLabel);
if (lLocalizedLabel) CFRelease(lLocalizedLabel);
}
CFRelease(lMap);
}
}
// SIP
{
ABMultiValueRef lMap = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonInstantMessageProperty);
if(lMap) {
for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i);
BOOL add = false;
if(CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
CFStringRef contactSipField = (CFStringRef)[LinphoneManager instance].contactSipField;
if (!contactSipField) {
contactSipField = CFStringCreateWithCString(NULL, "SIP", kCFStringEncodingMacRoman);
}
if(CFStringCompare(contactSipField, CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), kCFCompareCaseInsensitive) == 0) {
add = true;
}
} else {
add = true;
}
if(add) {
CFStringRef lValue = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
NSString* lNormalizedKey = [FastAddressBook normalizeSipURI:(NSString*)lValue];
if(lNormalizedKey != NULL) {
addressBookMap[lNormalizedKey] = lPerson;
} else {
addressBookMap[(NSString*)lValue] = lPerson;
}
/*
NSString *lValue =
(__bridge NSString *)CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
NSString *lNormalizedKey = [FastAddressBook normalizeSipURI:lValue];
if (lNormalizedKey != NULL) {
[addressBookMap setObject:(__bridge id)(lPerson)forKey:lNormalizedKey];
} else {
[addressBookMap setObject:(__bridge id)(lPerson)forKey:lValue];
}
*/
}
CFRelease(lDict);
}
CFRelease(lMap);
}
}
}
CFRelease(lContacts);
}
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneAddressBookUpdate object:self];
}
void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void *context) {
FastAddressBook* fastAddressBook = (FastAddressBook*)context;
[fastAddressBook loadData];
}
- (void)dealloc {
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self);
CFRelease(addressBook);
[addressBookMap release];
[super dealloc];
}
#end
P.S.:
-i use non-arc project
-zombie enable too but nothing change.
-Ivalue is will and thats because crash happening.
Debug Console:
warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available.
LinphoneAddress* linphoneAddress = linphone_core_interpret_url([LinphoneManager getLc], [address UTF8String]);
address is nil. Figure out why that is and you've got your crash source. It likely should be nil as it is probably an optional field in the original record.
That code is a bit of a mess, btw. It isn't following the standard patterns (lots of method prefixed with get, for example). It really should be modernized and have ARC enabled.
I'm trying to NSLog name and number from my contact in Address Book.
I succeed to log the name, but I don't succeed to solve the problem with number.
Here is my code :
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
if (addressBook != NULL) {
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (granted) {
CFArrayRef allNames = ABAddressBookCopyArrayOfAllPeople(addressBook);
if (allNames != NULL) {
NSMutableArray *names = [NSMutableArray array];
for (int i = 0; i < CFArrayGetCount(allNames); i++) {
ABRecordRef group = CFArrayGetValueAtIndex(allNames, i);
CFStringRef name = ABRecordCopyCompositeName(group);
[names addObject:(__bridge NSString *)name];
CFRelease(name);
}
NSLog(#"names = %#", names);
CFRelease(allNames);
}
}
CFRelease(addressBook);
});
}
Maybe I have to create NSDictionnary ? I don't know how to solve it...
The phone numbers are a ABMultiValueRef:
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
if (phones != NULL) {
for (NSInteger index = 0; index < ABMultiValueGetCount(phones); index++) {
NSString *phone = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, index));
NSString *label = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(phones, index)); // either kABHomeLabel or kABPersonPhoneMainLabel or ...
// do something with `phone` and `label`
}
CFRelease(phones);
}
You'll need to use ABRecordCopyValue(group, kABPersonPhoneProperty) which returns ABMultiValueRef. See https://stackoverflow.com/a/286281/171089 for more.
I have an app, that needs to get the user's contacts
providing the user gave access to the contacts
How do i get the exchange contacts ?
I tried the normal method of accessing the phone book, but i want to create my own ui
and in my own ui, only the local contacts appear
this is my code to get the contacts
- (void)reloadAddressBook
{
// Create addressbook data model
NSMutableArray *contactsTemp = [NSMutableArray array];
ABAddressBookRef addressBooks = [(TKPeoplePickerController*)self.navigationController addressBook];
CFArrayRef allPeople;
CFIndex peopleCount;
if (_group) {
self.title = _group.name;
ABRecordRef groupRecord = ABAddressBookGetGroupWithRecordID(addressBooks, (ABRecordID)_group.recordID);
allPeople = ABGroupCopyArrayOfAllMembers(groupRecord);
peopleCount = (CFIndex)_group.membersCount;
} else {
self.title = NSLocalizedString(#"All Contacts", nil);
allPeople = ABAddressBookCopyArrayOfAllPeople(addressBooks);
peopleCount = ABAddressBookGetPersonCount(addressBooks);
}
for (NSInteger i = 0; i < peopleCount; i++)
{
ABRecordRef contactRecord = CFArrayGetValueAtIndex(allPeople, i);
if (!contactRecord) continue;
CFStringRef abName = ABRecordCopyValue(contactRecord, kABPersonFirstNameProperty);
CFStringRef abLastName = ABRecordCopyValue(contactRecord, kABPersonLastNameProperty);
CFStringRef abFullName = ABRecordCopyCompositeName(contactRecord);
Contact *contact = [[Contact alloc] init];
NSString *fullNameString;
NSString *firstString = (__bridge NSString *)abName;
NSString *lastNameString = (__bridge NSString *)abLastName;
if ((__bridge id)abFullName != nil) {
fullNameString = (__bridge NSString *)abFullName;
} else {
if ((__bridge id)abLastName != nil)
{
fullNameString = [NSString stringWithFormat:#"%# %#", firstString, lastNameString];
}
}
if([fullNameString isEqualToString:#"אלי"]){
LogInfo(#"found eli");
}
contact.name = fullNameString;
contact.recordID = (int)ABRecordGetRecordID(contactRecord);
contact.rowSelected = NO;
contact.lastName = (__bridge NSString*)abLastName;
contact.firstName = (__bridge NSString*)abName;
ABPropertyID multiProperties[] = {
kABPersonPhoneProperty,
kABPersonEmailProperty
};
NSInteger multiPropertiesTotal = sizeof(multiProperties) / sizeof(ABPropertyID);
for (NSInteger j = 0; j < multiPropertiesTotal; j++) {
ABPropertyID property = multiProperties[j];
ABMultiValueRef valuesRef = ABRecordCopyValue(contactRecord, property);
NSInteger valuesCount = 0;
if (valuesRef != nil) valuesCount = ABMultiValueGetCount(valuesRef);
if (valuesCount == 0) {
CFRelease(valuesRef);
continue;
}
for (NSInteger k = 0; k < valuesCount; k++) {
CFStringRef value = ABMultiValueCopyValueAtIndex(valuesRef, k);
switch (j) {
case 0: {// Phone number
contact.tel = [(__bridge NSString*)value telephoneWithReformat];
break;
}
case 1: {// Email
contact.email = (__bridge NSString*)value;
break;
}
}
CFRelease(value);
}
CFRelease(valuesRef);
if(contact.tel.length == 0){
continue;
}
}
[contactsTemp addObject:contact];
if (abName) CFRelease(abName);
if (abLastName) CFRelease(abLastName);
if (abFullName) CFRelease(abFullName);
}
if (allPeople) CFRelease(allPeople);
// Sort data
UILocalizedIndexedCollation *theCollation = [UILocalizedIndexedCollation currentCollation];
SEL sorter = ABPersonGetSortOrdering() == kABPersonSortByFirstName ? NSSelectorFromString(#"sorterFirstName") : NSSelectorFromString(#"sorterLastName");
for (TKContact *contact in contactsTemp) {
NSInteger sect = [theCollation sectionForObject:contact
collationStringSelector:sorter];
contact.sectionNumber = sect;
}
NSInteger highSection = [[theCollation sectionTitles] count];
NSMutableArray *sectionArrays = [NSMutableArray arrayWithCapacity:highSection];
for (int i=0; i<=highSection; i++) {
NSMutableArray *sectionArray = [NSMutableArray arrayWithCapacity:1];
[sectionArrays addObject:sectionArray];
}
for (TKContact *contact in contactsTemp) {
[(NSMutableArray *)[sectionArrays objectAtIndex:contact.sectionNumber] addObject:contact];
}
for (NSMutableArray *sectionArray in sectionArrays) {
NSArray *sortedSection = [theCollation sortedArrayFromArray:sectionArray collationStringSelector:sorter];
[_listContent addObject:sortedSection];
}
[self.tableView reloadData];
}
Let me introduce my functionality of App,I use push notification & addressbook and CoreTelephony Framework.
What I am doing in my application is , When i get Push notification, I save the number from the Payload in a Appdelegate Variable(Incoming_NO) , if there is no Such contact with this number , Ill create the new contact and save it.
When i receive the Call , the same contact name appears as i added before , Later on I am allowing the user to Edit the Contact if he want to save the contact or to delete , When he edit the contact and later when i receive the Push notification with same number I am getting the exc_bad_access to (Incoming_NO) I have enabled the Zombie and i got the breakpoint error at the same place ..
Can anyone help me what is the issue .
Received notification: {
aps = {
alert = "Please help me-+918884718240";
sound = "beep.caf";
};
}
Code :
NSString* alertValue = [[userInfo valueForKey:#"aps"] valueForKey:#"alert"];
NSRange range=[alertValue rangeOfString:#":"];
NSString *param,*msg;
NSRange range1=[alertValue rangeOfString:#":"];
if (range1.location != NSNotFound)
{
param = [alertValue substringFromIndex:range1.location + range1.length];
msg=[alertValue substringToIndex:range.location + range.length-1];
}
else
{
range1=[alertValue rangeOfString:#"-"];
if (range1.location != NSNotFound)
{
param = [alertValue substringFromIndex:range1.location + range1.length];
msg=[alertValue substringToIndex:range1.location + range1.length-1];
}
}
if(range.length!=0)
{
parts= [NSMutableArray arrayWithArray:[alertValue componentsSeparatedByString:#":"]];
}else
{
parts = [NSMutableArray arrayWithArray:[alertValue componentsSeparatedByString:#"-"]];
}
incoming_Number =[parts objectAtIndex:1];
For this Variable(incoming_Number) I get the error when i receive the Push notification after saving the contact.
I tried to change incoming_Number type to NSString and NSMutableString , still the same error , I guess what happening is I am referring to the object which is released . But in debugger I can see it has the value.
Adding Contact Code:
- (void)setContacts:(UIImage *) imgdata :(NSString *)incoming_number {
ABRecordRef person=NULL;
ABRecordRef loopingPerson=NULL;
_Bool vizzical_present=false;
CFErrorRef myError = NULL;
NSArray *allContacts;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &myError);
// ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil, nil);
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
//dispatch_release(sema);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
if (accessGranted) {
// int count = (int) ABAddressBookGetPersonCount(addressBook);
allContacts = (__bridge_transfer NSArray
*)ABAddressBookCopyArrayOfAllPeople(addressBook);
for(CFIndex i = 1; i < allContacts.count; i++)
{
loopingPerson = (__bridge ABRecordRef)allContacts[i];
CFStringRef firstName;
// char *lastNameString, *firstNameString;
firstName = ABRecordCopyValue(loopingPerson, kABPersonFirstNameProperty);
if([(__bridge NSString *)(firstName) isEqualToString:#"VizziCal"]){
vizzical_present=true;
}
ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(loopingPerson, kABPersonPhoneProperty);
// NSMutableArray *numbersArray = [[NSMutableArray alloc] init];
// CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNumbers, 0 );
CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNumbers, 0 );
NSString* noSpaces =
[[(__bridge NSString *)phoneNumberValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]componentsJoinedByString:#""];
if(phoneNumberValue!=NULL){
NSString* noHypen =
[noSpaces stringByReplacingOccurrencesOfString:#"-" withString:#""];
// CFStringRef phoneNumberLocalizedLabel = ABAddressBookCopyLocalizedLabel( phoneNumberLabel );
// NSString *addPlus=[[NSString alloc]initWithFormat:#"%#",incoming_number] ;
if([incoming_number isEqual:noHypen] || ([incoming_number rangeOfString:noHypen].location!=NSNotFound)){
NSLog(#"%# and %# and %ld",incoming_number,noHypen,i);
person=loopingPerson;
break;
}
}
}
if(person!=NULL){
CFErrorRef error = nil;
CFDataRef imageData = ABPersonCopyImageData(person);
NSData* imageData1 = (__bridge NSData*)ABPersonCopyImageData(person);
UIImage *image = [UIImage imageWithData:(__bridge NSData *)(imageData)];
UIImage *image1 = [UIImage imageWithData:(NSData *)(imageData1)];
NSData *dataRef;
UIImage *mergedImage;
if(image!=NULL)
{
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
savedImagePath= [self saveImage:image1 forPerson:#"image"];
});
dataRef = UIImagePNGRepresentation(imgdata);
CFRelease(imageData);
}
else{
if(imgdata.size.height <480 && imgdata.size.width<320)
{
UIImage *image = [UIImage imageNamed:#"blank_image.png"];
mergedImage=[self mergeTwoImages:imgdata :image];
CGFloat width = imgdata.size.width;
CGFloat height = imgdata.size.height;
NSLog(#"Height:%f and Width =%f",width,height);
dataRef = UIImagePNGRepresentation(mergedImage);
}
else{
dataRef = UIImagePNGRepresentation(imgdata);
}
}
CFDataRef cfDataRef = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);
if (ABPersonHasImageData(person)) {
ABPersonRemoveImageData(person, &error);
ABAddressBookSave(addressBook, &error);
}
//ABRecordSetValue(person, kABPersonFirstNameProperty, #"Don Juan", NULL);
// ABAddressBookAddRecord(addressBook, person, &error);
if (ABPersonSetImageData(person, cfDataRef, &error)) {
if (ABAddressBookHasUnsavedChanges(addressBook)) {
NSLog(#"has unsaved changes");
} else {
NSLog(#"nothing to save");
}
if (ABAddressBookSave(addressBook, &error)) {
NSLog(#"saved");
} else {
NSLog(#"not saved");
}
}
}
else{
if(!vizzical_present)
{
ABRecordRef newPerson = ABPersonCreate();
ABRecordSetValue(newPerson, kABPersonFirstNameProperty, #"VizziCal", &myError);
CFDataRef dataRef = (__bridge CFDataRef)(UIImagePNGRepresentation(imgdata));
[prefs setBool:YES forKey:#"contact-created"];
//Phone number is a list of phone number, so create a multivalue
ABMutableMultiValueRef phoneNumberMultiValue =
ABMultiValueCreateMutable(kABPersonPhoneProperty);
ABMultiValueAddValueAndLabel(phoneNumberMultiValue ,(__bridge CFTypeRef)(incoming_number),kABPersonPhoneMobileLabel, NULL);
// ...
// Set other properties
ABRecordSetValue(newPerson, kABPersonPhoneProperty, phoneNumberMultiValue, &myError);
// ...
ABAddressBookAddRecord(addressBook, newPerson, &myError);
ABAddressBookSave(addressBook, &myError);
if (myError != NULL)
{
CFStringRef errorDesc = CFErrorCopyDescription(myError);
NSLog(#"Contact not saved: %#", errorDesc);
CFRelease(errorDesc);
}
if (ABPersonSetImageData(newPerson, dataRef, &myError)) {
if (ABAddressBookHasUnsavedChanges(addressBook)) {
NSLog(#"has unsaved changes");
} else {
NSLog(#"nothing to save");
}
if (ABAddressBookSave(addressBook, &myError)) {
NSLog(#"saved");
} else {
NSLog(#"not saved");
}
}
CFRelease(newPerson);
CFRelease(addressBook);
CFRelease(phoneNumberMultiValue);
}
else
{
ABRecordRef newPerson = ABPersonCreate();
for(CFIndex i = 1; i < allContacts.count; i++)
{
loopingPerson = (__bridge ABRecordRef)allContacts[i];
CFStringRef firstName;
// char *lastNameString, *firstNameString;
firstName = ABRecordCopyValue(loopingPerson, kABPersonFirstNameProperty);
NSString *name=(__bridge NSString *)(firstName);
if([name isEqualToString:#"VizziCal"])
break;
}
if(loopingPerson !=NULL )
{
[prefs setBool:YES forKey:#"contact-created"];
CFDataRef dataRef = (__bridge CFDataRef)(UIImagePNGRepresentation(imgdata));
//Phone number is a list of phone number, so create a multivalue
ABMutableMultiValueRef phoneNumberMultiValue =
ABMultiValueCreateMutable(kABPersonPhoneProperty);
ABMultiValueAddValueAndLabel(phoneNumberMultiValue ,(__bridge CFTypeRef)(incoming_number),kABPersonPhoneMobileLabel, NULL);
// ...
// Set other properties
ABRecordSetValue(newPerson, kABPersonPhoneProperty, phoneNumberMultiValue, &myError);
// ...
ABAddressBookAddRecord(addressBook, newPerson, &myError);
ABAddressBookSave(addressBook, &myError);
if (myError != NULL)
{
CFStringRef errorDesc = CFErrorCopyDescription(myError);
NSLog(#"Contact not saved: %#", errorDesc);
CFRelease(errorDesc);
}
if (ABPersonSetImageData(newPerson, dataRef, &myError)) {
if (ABAddressBookHasUnsavedChanges(addressBook)) {
NSLog(#"has unsaved changes");
} else {
NSLog(#"nothing to save");
}
if (ABAddressBookSave(addressBook, &myError)) {
NSLog(#"saved");
} else {
NSLog(#"not saved");
}
}
CFRelease(newPerson);
CFRelease(addressBook);
CFRelease(phoneNumberMultiValue);
}
}
}
}
}
Here what I am doing is , I am checking whether Person Exist or not , if not I am checking for the default contact "VizziCal" if that doesnt exist then I am creating the New contact as "VizziCal".
First Rather doing all this stuff for getting Incoming No, Try Custom Payload for this.
It is simple.
Take a look Push Notification Programming Guide
you could try:
{ "alert": "Please help me", "phone": "9999999999" }
NOTE: This will created at server side.