EXC_BAD_ACCESS crash when start running app? - ios
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.
Related
In a try to fix NSRangeException error
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'; }
how to re-encode data from CFFTPCreateParsedResourceListing function?
i try to communicate with FTP server using CFNetwork.framework. using CFFTP API(CFWriteStreamCreateWithFTPURL function), i get a NSData of specific URL. then i start to parse the NSData with CFFTPCreateParsedResourceListing function, it gives me poorly encoded filenames.(when the file name is Korean) all character in Korean is converted to question mark(?). how can i fix this? please give me some advice. thank you in advance. NSMutableArray * newEntries; NSUInteger offset; newEntries = [NSMutableArray array]; assert(newEntries != nil); offset = 0; do { CFIndex bytesConsumed; CFDictionaryRef thisEntry; thisEntry = NULL; assert(offset <= [self.listData length]); bytesConsumed = CFFTPCreateParsedResourceListing(NULL, &((const uint8_t *) self.listData.bytes)[offset], (CFIndex) ([self.listData length] - offset), &thisEntry); if (bytesConsumed > 0) { if (thisEntry != NULL) { NSDictionary * entryToAdd; entryToAdd = [self entryByReencodingNameInEntry:(__bridge NSDictionary *) thisEntry encoding:NSUTF8StringEncoding]; [newEntries addObject:entryToAdd]; } offset += (NSUInteger) bytesConsumed; } if (thisEntry != NULL) { CFRelease(thisEntry); } if (bytesConsumed == 0) { break; } else if (bytesConsumed < 0) { [self stopReceiveWithStatus:#"Listing parse failed"]; break; } } while (YES); below code is entryByReencodingNameInEntry method NSDictionary * result; NSString * name; NSData * nameData; NSString * newName; newName = nil; // Try to get the name, convert it back to MacRoman, and then reconvert it // with the preferred encoding. name = [entry objectForKey:(id) kCFFTPResourceName]; if (name != nil) { assert([name isKindOfClass:[NSString class]]); nameData = [name dataUsingEncoding:NSMacOSRomanStringEncoding]; if (nameData != nil) { newName = [[NSString alloc] initWithData:nameData encoding:newEncoding]; } } if (newName == nil) { assert(NO); // in the debug builds, if this fails, we should investigate why result = (NSDictionary *) entry; } else { NSMutableDictionary * newEntry; newEntry = [entry mutableCopy]; assert(newEntry != nil); [newEntry setObject:newName forKey:(id) kCFFTPResourceName]; result = newEntry; } return result; for example, if a folder has 3 files 애플.txt, 삼성.txt, 테스트.txt -> converted to ??.txt, ??.txt, ???.txt
Memory leak in ios cordova contacts plugin?
Here's the source code for the method that appears to be causing the leak. - (void)search:(CDVInvokedUrlCommand*)command { NSString* callbackId = command.callbackId; NSArray* fields = [command argumentAtIndex:0]; NSDictionary* findOptions = [command argumentAtIndex:1 withDefault:[NSNull null]]; [self.commandDelegate runInBackground:^{ // from Apple: Important You must ensure that an instance of ABAddressBookRef is used by only one thread. // which is why address book is created within the dispatch queue. // more details here: http: //blog.byadrian.net/2012/05/05/ios-addressbook-framework-and-gcd/ CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init]; CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles // it gets uglier, block within block..... [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) { if (addrBook == NULL) { // permission was denied or other error - return error CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? (int)errCode.errorCode:UNKNOWN_ERROR]; [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; return; } NSArray* foundRecords = nil; // get the findOptions values BOOL multiple = NO; // default is false NSString* filter = nil; NSArray* desiredFields = nil; if (![findOptions isKindOfClass:[NSNull class]]) { id value = nil; filter = (NSString*)[findOptions objectForKey:#"filter"]; value = [findOptions objectForKey:#"multiple"]; if ([value isKindOfClass:[NSNumber class]]) { // multiple is a boolean that will come through as an NSNumber multiple = [(NSNumber*)value boolValue]; // NSLog(#"multiple is: %d", multiple); } desiredFields = [findOptions objectForKey:#"desiredFields"]; // return all fields if desired fields are not explicitly defined if (desiredFields == nil || desiredFields.count == 0) { desiredFields = [NSArray arrayWithObjects:#"*", nil]; } } NSDictionary* searchFields = [[CDVContact class] calcReturnFields:fields]; NSDictionary* returnFields = [[CDVContact class] calcReturnFields:desiredFields]; NSMutableArray* matches = nil; if (!filter || [filter isEqualToString:#""]) { // get all records foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); if (foundRecords && ([foundRecords count] > 0)) { // create Contacts and put into matches array // doesn't make sense to ask for all records when multiple == NO but better check int xferCount = multiple == YES ? (int)[foundRecords count] : 1; matches = [NSMutableArray arrayWithCapacity:xferCount]; for (int k = 0; k < xferCount; k++) { CDVContact* xferContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:k]]; [matches addObject:xferContact]; xferContact = nil; } } } else { foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); matches = [NSMutableArray arrayWithCapacity:1]; BOOL bFound = NO; int testCount = (int)[foundRecords count]; for (int j = 0; j < testCount; j++) { CDVContact* testContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:j]]; if (testContact) { bFound = [testContact foundValue:filter inFields:searchFields]; if (bFound) { [matches addObject:testContact]; } testContact = nil; } } } NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1]; if ((matches != nil) && ([matches count] > 0)) { // convert to JS Contacts format and return in callback // - returnFields determines what properties to return #autoreleasepool { int count = multiple == YES ? (int)[matches count] : 1; for (int i = 0; i < count; i++) { CDVContact* newContact = [matches objectAtIndex:i]; NSDictionary* aContact = [newContact toDictionary:returnFields]; [returnContacts addObject:aContact]; } } } // return found contacts (array is empty if no contacts found) CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:returnContacts]; [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId]; // NSLog(#"findCallback string: %#", jsString); if (addrBook) { CFRelease(addrBook); } }]; }]; // end of workQueue block return; } The specific line that is doing most of the leaking is foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);, but this is confusing, given that the correct __bridge_transfer call is used. What's going on here?
App Crash with exc_bad_access code
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.
Gamekit Framework: sending an int?
Hi I am building a game that uses the gamekit framework but I am having trouble sending to int using the "sendDataToAllPlayers", it cannot distinguish between the two int that I am sending. Here is some of my code: typedef enum { kMessageTypeRandomNumber = 0, kMessageQN = 0, kMessageTypeGameBegin, kMessageTypeSelectAnswer1, kMessageTypeSelectAnswer2, kMessageTypeSelectAnswer3, kMessageTypeGameOver } MessageType; typedef struct { MessageType messageType; } Message; typedef struct { Message message; uint32_t randomNumber; int SelectedQ; } MessageRandomNumber; the following is the send methods: -(void)sendTheSelectedRandomQuestionWithQuestion { MessageRandomNumber message; message.message.messageType = kMessageQN; message.SelectedQ = randomSelectedQuestion; NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageRandomNumber)]; [self sendData:data]; } - (void)sendRandomNumber { //ourRandom = arc4random()%100; MessageRandomNumber message; message.message.messageType = kMessageTypeRandomNumber; message.randomNumber = ourRandom; NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageRandomNumber)]; [self sendData:data]; } - (void)sendData:(NSData *)data { NSError *error; BOOL success = [[GCHelper sharedInstance].match sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error]; if (!success) { NSLog(#"Error sending init packet"); [self matchEnded]; } } the following is the didreceivedatamethod: - (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID { //Store away other player ID for later if (otherPlayerID == nil) { otherPlayerID = playerID; } Message *message = (Message *) [data bytes]; if (message->messageType == kMessageQN) { NSLog(#"Received The Selected Question To Display"); debugLabel.text = #"received the selected q"; MessageRandomNumber * messageSelectedQuestion = (MessageRandomNumber *) [data bytes]; NSLog(#"The Selected Question is number: %ud",messageSelectedQuestion->SelectedQ); randomSelectedQuestion = messageSelectedQuestion->SelectedQ; [self displayTheSlectedQuestion]; } else if (message->messageType == kMessageTypeRandomNumber) { MessageRandomNumber * messageInit = (MessageRandomNumber *) [data bytes]; NSLog(#"Received random number: %ud, ours %ud", messageInit->randomNumber, ourRandom); bool tie = false; if (messageInit->randomNumber == ourRandom) { //NSLog(#"TIE!"); ourRandom = arc4random(); tie = true; [self sendRandomNumber]; } else if (ourRandom > messageInit->randomNumber) { NSLog(#"We are player 1"); isPlayer1 = YES; //[self sendTheSelectedRandomQuestionWithQuestion]; } else { NSLog(#"We are player 2"); isPlayer1 = NO; } if (!tie) { receivedRandom = YES; if (gameState == kGameStateWaitingForRandomNumber) { [self setGameState:kGameStateWaitingForStart]; } [self tryStartGame]; } } } } but for some mysterious reason every time I call the sendTheSelectedRandomQuestionWithQuestion when it is received it thinks that it is randomNumber and not SelectedQ? Can anyone help me please?
Ok, just figured out the problem. It should be: typedef enum { kMessageTypeRandomNumber = 0, kMessageQN = 1, kMessageTypeGameBegin, kMessageTypeSelectAnswer1, kMessageTypeSelectAnswer2, kMessageTypeSelectAnswer3, kMessageTypeGameOver } MessageType; Instead of: typedef enum { kMessageTypeRandomNumber = 0, kMessageQN = 0, kMessageTypeGameBegin, kMessageTypeSelectAnswer1, kMessageTypeSelectAnswer2, kMessageTypeSelectAnswer3, kMessageTypeGameOver } MessageType;