I understand what the error EXC_BAD_ACCESS
means in general, but I'm puzzled about what's happening in my case.
I have a custom class which has an NSComparator
property sortWithThisComparator
. If that property is set by the user, when I insert an item into the instance's class property array items
I use the comparator to determine the insertion location:
- (void) insertItem:(id<NSCoding, CKArchivingItem>) item {
if (arrayObjectClassString && ![item isKindOfClass:NSClassFromString(arrayObjectClassString)]) {
[NSException raise:@"YOU MADE A MISTAKE" format:@"you tried to insert a %@ but I can only accept %@", [item class], arrayObjectClassString];
} else {
if (!sortWithThisComparator) {
[self.items addObject:item];
} else {
NSInteger newItemIndex = [self.items indexOfObject:item inSortedRange:NSMakeRange(0, [self.items count]) options:NSBinarySearchingFirstEqual usingComparator:sortWithThisComparator];
if (newItemIndex >= [self.items count]) {
[self.items addObject:items];
} else {
[self.items insertObject:item atIndex:newItemIndex];
}
}
}
}
Everything works fine when I don't set a comparator, but when I do use the comparator I get a bad access error:
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);
...
[[CKGenericSingletonSubclass sharedManager] setSortWithThisComparator: ^NSComparisonResult(CKGeneralizedItemSubclass *i1, CKGeneralizedItemSubclass *i2) {
NSLog(@"we are inside");
NSLog(@"here is the item 1 %@", i1);
NSLog(@"we are comparing this float %f to thisf loat %f", i1.gradeSchoolAverage, i2.gradeSchoolAverage);
if (i1.gradeSchoolAverage < i2.gradeSchoolAverage) {
return NSOrderedAscending;
} else if (i1.gradeSchoolAverage == i2.gradeSchoolAverage) {
return NSOrderedSame;
} else {
return NSOrderedDescending;
}
}];
I get a bad access thread on the second line of the comparator, which is simply logging one of the parameters passed via the NSComparator. Yet the class instances I am passing to the insertItem
are accessible elsewhere without this problem, so I know they have been properly instantiated and are otherwise properly passed since I can insert them into the items
property fine without a comparator. What am I missing here?
Further details. I am storing the NSComparator as
@property (strong, atomic) NSComparator sortWithThisComparator;
Actually, I only can make some assumptions according to the codes you mentioned above.
For the first block, I guess self.items is a mutable array. Also in the function insertItem:
, once sortWithThisComparator
is not nil, new object will be inserted after a sorting process gets an index.
Because you get a bad access on thread issues, I guess you didn't take care of threading very well in your codes.
Here are some suggestion:
Ex:
- (void)addItem:(id)item {
dispatch_async(self.queue, ^{
[threadLock lock];
[self.items addObject:item];
[threadLock unlock];
}
}
Let's take a look of this line:
NSInteger newItemIndex = [self.items indexOfObject:item inSortedRange:NSMakeRange(0, [self.items count]) options:NSBinarySearchingFirstEqual usingComparator:sortWithThisComparator];
In my opinion, I would do an array copy first and set options with NSBinarySearchingInsertionIndex
:
NSArray *array = [self.items copy];
NSInteger newItemIndex = [array indexOfObject:item inSortedRange:NSMakeRange(0, [array count]) options:NSBinarySearchingInsertionIndex usingComparator:sortWithThisComparator];
NSMakeRange(0, self.items.count)
.
Probably also revise the condition little bit in function
insertItem:
,if (!sortWithThisComparator || self.items.count == 0) {}
These are some thoughts I have at this movement. I'll add more once I get ideas for other possibilities.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With