Objective C - Subclassing NSArray
Asked Answered
O

5

5

I am trying to subclass NSArray, but it crashes the app when trying to access the count method. I know that NSArray is a class cluster.

  • But what does this mean?
  • Is there a work around to be able to subclass an NSArray?

I know that I can simply subclass NSObject and have my array as an instance variable but I would rather subclass NSArray.

EDIT: Reason: I am creating a card game, I have a class Deck which should subclass NSMutableArray to have a couple of extra methods (-shuffle, -removeObjects:, -renew, etc), and I think it will look cleaner to subclass NSArray rather than having a var.

Oneal answered 4/12, 2010 at 1:35 Comment(3)
why do you need to subclass it?Mihalco
I might just create a category to add the extra methods instead of subclassing :(Oneal
+1 for categories. Subclassing NS*Array for this is serious overkill that Objective-C categories makes completely unnecessary.Labio
K
17

The problem with adding a category on a class like this is that all instances of the class will inherit the additional methods. That's both unnecessary (since not every array needs to be able to be shuffled, etc.) and dangerous (because you can't benefit from typechecking to be sure the NSArray you're currently referring to is really one that was expected to be shuffled).

An alternative would be to create your own Deck class that has an NSMutableArray as an instance variable. There you can define actions on your deck exactly as you would like, and the fact that you are using an NSMutableArray becomes an implementation detail. This lets you take advantage of typechecking at compile-time and it lets you change the internal implementation of your Deck class without changing its clients. For instance, if you decided for some reason that an NSMutableDictionary would be a better backing store, you can make all those changes within the implementation of your Deck class without changing any of the code that creates and uses the Deck.

Kearse answered 4/12, 2010 at 2:38 Comment(1)
I don't think he's implying there's a technical overhead, he's just saying that every instance gains the functionality of your "subclass", whether it's relevant or not. For example, accidentally calling "-shuffle" on an NSArray of unintended objects may or may not work and shouldn't be allowed.Cule
A
7

You usually won't need to subclass it, but in any case the suggestions made by Apple are:

Any subclass of NSArray must override the primitive instance methods count and objectAtIndex:. These methods must operate on the backing store that you provide for the elements of the collection. For this backing store you can use a static array, a standard NSArray object, or some other data type or mechanism. You may also choose to override, partially or fully, any other NSArray method for which you want to provide an alternative implementation.

Did you actually override countmethod? As they say you have to provide your own backing structure to hold array elements, and override suggested methods considering this..

Amid answered 4/12, 2010 at 1:38 Comment(2)
mm i tried overriding count, and calling [super count] but that didn't workOneal
you should provide your own backing array, not relying on the one already provided by NSArray, otherwise you could just use a NSArray as a instance variable and map the original count to the inner NSArray countAmid
U
3

If you're just adding new methods, and using the existing backing store, then a better approach is to add a category to NSArray. Categories are a really powerful part of objective-C - see cocoadev for some samples.

Udale answered 4/12, 2010 at 1:53 Comment(1)
Adding a category to NSArray to add app-specific functionality is generally a bad idea.Ripley
A
0

NSMutableArray already has a - (void)removeObjectsInArray:(NSArray *)otherArray; You're going to be best off making an NSObject subclass with a mutable array property.

Artemis answered 4/12, 2010 at 4:16 Comment(0)
J
-1

In this particular case, I'd shuffle the array using -sortedArrayUsingComparator: and make your comparator randomly return NSOrderedAscending or NSOrderedDescending.

E.G:

NSArray *originalArray; // wherever you might get this.
NSArray *shuffledArray = [orginalArray sortedArrayUsingComparator:
    ^(id obj1, id obj2) { 
     return random() %  2 ? NSOrderedAscending : NSOrderedDescending;
     }];
Jittery answered 4/12, 2010 at 4:8 Comment(3)
Pretty sure that won't work as it'll never settle on a stable state.Ripley
Actually, it does work. Shuffling an array containing @"A"..@"J" ends up calling the comparator block 19 times.Jittery
Wrong. Sorting algorithms need a total order, that is exactly one of a > b, a < b or a == b is true. Your predicate doesn't satisfy this requirement, so the shuffling algorithm is flawed.Hide

© 2022 - 2024 — McMap. All rights reserved.