Objective-c noob here. I'm experiencing a EXC_BAD_ACCESS error in my tests and can't figure out why. I've written a Cart class for my application representing a user's cart. A Cart can have multiple Orders, stored in an array. I'm attempting to implement KVO compliance for the Orders array with the given code (Apologies for the long code snippet, want to make sure everything is present to resolve the problem). The .h file:
#import "Model.h"
@class Item;
@class Organization;
@class Order;
@interface Cart : NSObject
@property (copy, readonly, nonatomic) NSArray *orders;
- (instancetype) init __attribute__((unavailable("init not available. Use `sharedCart`.")));
+ (instancetype)sharedCart;
- (void)setItem:(Item *)item withQuantity:(NSNumber *)quantity;
- (void)removeItem:(Item *)item;
- (NSNumber *)itemCount;
- (Order *)orderForSeller:(Organization *)seller;
@end
And the .m:
@interface Cart()
- (void)addOrder:(Order *)order;
- (void)removeOrder:(Order *)order;
@property (copy, readwrite, nonatomic) NSArray *orders;
@end
NSString * const ordersKey = @"orders";
@implementation Cart
{
NSMutableArray *_orders;
}
@synthesize orders = _orders;
+ (instancetype)sharedCart {
static dispatch_once_t onceToken;
static Cart *cart;
dispatch_once(&onceToken, ^{
cart = [[Cart alloc] initPrivate];
});
return cart;
}
- (void)insertObject:(Order *)order inOrdersAtIndex:(NSUInteger)index {
[_orders insertObject:order atIndex:index];
}
- (void)removeObjectFromOrdersAtIndex:(NSUInteger)index {
[_orders removeObjectAtIndex:index];
}
- (void)setOrders:(NSArray *)array {
if (array != _orders) {
_orders = [array mutableCopy];
}
}
- (instancetype)initPrivate {
self = [super init];
if (self) {
self = [super init];
_orders = [[NSMutableArray alloc] init];
}
return self;
}
+ (instancetype)object {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Can not create new Cart instance. Used [Cart sharedCart]" userInfo:nil];
}
-(Order *)orderForSeller:(Organization *)seller {
for (Order *order in self.orders) {
if ([order.seller is:seller]) {
return order;
}
}
return nil;
}
- (void)setItem:(Item *)item withQuantity:(NSNumber *)quantity {
Order *order = [self orderForSeller:item.seller];
if (!order) {
order = [Order object];
order.seller = item.seller;
order.user = [User currentUser];
[self addOrder:order];
}
[order setItem:item withQuantity:quantity];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// If an order is ever empty, remove it from cart.
if ([object isKindOfClass:[Order class]] && [keyPath isEqualToString:@"orderItems"]) {
Order *order = (Order *)object;
if ([[order itemCount] integerValue] == 0) {
[self removeOrder:order];
}
}
// When orders are saved, remove them from cart.
if ([object isKindOfClass:[Order class]] && [keyPath isEqualToString:@"isNew"]) {
Order *order = (Order *)object;
BOOL orderHasBeenPlaced = ![order isNew];
if (orderHasBeenPlaced) {
[self removeOrder:order];
}
}
}
- (void)addOrder:(Order *)order {
[order addObserver:self forKeyPath:@"orderItems" options:NSKeyValueObservingOptionNew context:nil];
[order addObserver:self forKeyPath:@"isNew" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
[self insertObject:order inOrdersAtIndex:[_orders count]];
}
-(void)removeOrder:(Order *)order {
[order removeObserver:self forKeyPath:@"orderItems"];
[order removeObserver:self forKeyPath:@"isNew"];
NSUInteger index = [_orders indexOfObject:order];
[self removeObjectFromOrdersAtIndex:index];
}
-(void)removeItem:(Item *)item {
Order *order = [self orderForSeller:item.seller];
if (order) {
[order removeItem:item];
}
}
-(NSNumber *)itemCount {
return [self.orders valueForKeyPath:@"@sum.itemCount"];
}
- (void)dealloc {
for (Order *order in self.orders) {
[order removeObserver:self forKeyPath:@"isNew"];
[order removeObserver:self forKeyPath:@"orderItems"];
}
}
@end
The addOrder: method is producing the EXC_BAD_ACCESS exception on this line:
[self insertObject:order inOrdersAtIndex:[_orders count]];
Debugging, the _orders array is a valid NSMutableArray. Anyone have any idea what's going on? Much appreciated.
`