我发现了一个错误:
致命异常:NSRangeException *** - [__ NSArrayI objectAtIndex:]:索引1330超出界限[0 .. 1329]
字符串
NSArray *currentABRecords = [ApplicationPhoneDirectory records];
ApplicationPhoneDirectory
是NSObject
,具有唯一的联系人(字典和数组)。
但我认为错误是关于使用内存,如何更正确地管理它以避免出现这样的问题?
或者,如果我不正确,我可以将records
部分放在那里。
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';
}