I made a mistake while creating a TableView class
, and accidentally kept my @property
as copy
when I defined it:
@property (copy, nonatomic) NSMutableArray *words;
I initialised the array "correctly": (note this is the third attempt, so please ignore the fact that I'm not using mutableCopy and other better ways of doing this)
NSArray *fixedWords = @[@"Eeny", @"Meeny", @"Miny", @"Moe", @"Catch", @"A", @"Tiger", @"By", @"His", @"Toe"]; NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords]; self.words = mutWords;
However when I later came to reorder the array, it crashed on the removeObjectAtIndex line:
id object = [self.words objectAtIndex:fromIndexPath.row]; NSUInteger from = fromIndexPath.row; NSUInteger to = toIndexPath.row; [self.words removeObjectAtIndex:from];
With the error message
unrecognized selector sent to instance
Took a lot of digging to figure out that this is because the copy means that assigning the NSMutableArray results in creation of a standard (nonmutable) NSArray. Can anyone explain why this is the correct behaviour?
-copy, as implemented by mutable Cocoa classes, always returns their immutable counterparts. Thus, when an NSMutableArray is sent -copy, it returns an NSArray containing the same objects.
Because words
has the memory qualifier copy
, this line:
NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords]; self.words = mutWords;
Expands out to:
NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords]; self.words = [mutWords copy];
Given that NSMutableArray is a subclass of NSArray, the compiler doesn't complain, and you now have a ticking time bomb on your hands because NSArray does not recognize it's mutable subclass' methods (because it cannot mutate it's contents).
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