views:

340

answers:

2

I added a category to NSArray with a helper method for sorting. My unit tests all pass, but when running the app in the simulator it blows up. Could this be because of the NSMutableArray / NSCFArray class cluster stuff?

Here is the error: 'NSInvalidArgumentException', reason: '* -[NSCFArray sortBySequenceAsc]: unrecognized selector sent to instance 0x489c1f0'

Anyway, what is the proper way to add a category to NSArray and NSMutableArray?

@interface NSArray (Util) 
- (NSArray *)sortBySequenceAsc;
@end 

@implementation NSArray (Util)
- (NSArray *)sortBySequenceAsc {
    //my custom sort code here
}
@end
+2  A: 

The recommended way is to create a new object containing an NSArray. Underneath NSArray there's a lot of gunk that Apple doesn't tell us about; when you add new methods, you're unable to access that stuff, leading to errors.

Basically, do this:

@interface MySortingArray : NSObject {
     NSArray *theArray
}

- (int)count;
- (NSArray *)sortBySequenceAsc;

@end

@implementation MySortingArray

- (int)count {
    return [theArray count];
}

- (NSArray *)sortBySequenceAsc {
   // your code
}

@end
Chris Long
Alright. I will stay away from adding methods directly to NSArray.
Tony Eichelberger
How on earth would creating a category on NSArray make the object "unable to access" this "lot of gunk"?
Chuck
Well, I admit I did simplify it a lot. I meant that the *OP* would have difficulty knowing the intricacies of `NSCFArray` and co., since Apple gives you no documentation of it. It would really be more trouble than it's worth.
Chris Long
While this approach will work, I do not believe this is the *correct* approach for extending `NSArray` functionality. For more information, see my answer.
Dave DeLong
One problem with this approach is that you can't pass a `MySortingArray` object to any method that requires an `NSArray` as a parameter.
Dave DeLong
If that's necessary, you can always write `[myObject arrayMethod: sortingArray.theArray];` to gain access to the array within (assuming you made a `@property`, of course).
Chris Long
+4  A: 

I've used categories on NSArray many times with no problems, so I'm guessing your problem lies elsewhere (since your category looks correct).

Since you're getting an "unrecognized selector" error, that means the runtime doesn't know about your category, which means it wasn't linked into your binary. I would check and make sure your category's .m file is included in the appropriate target, clean, and build again.

EDIT: for example, this blog post shows how to create a category for NSArray for creating a shuffled copy of the original array.

EDIT #2: Apple's documentation on categories uses the specific example of extending the functionality of NSArray, so I find it difficult to believe that the "recommended" approach would be to wrap the array in a helper object. Citation (search the page for the five "NSArray" references)

Dave DeLong
I tried adding a category once and got the same problem as the OP. I read on some iPhone dev site that creating a new object containing an `NSArray` is recommended by Apple in this case; perhaps you're just more careful with your code. ;)
Chris Long
@Chris - Do you have a link to support the wrapper recommendation? I've never heard of that before and I'd be interested to learn more. :)
Dave DeLong
Sorry, it was a long time ago. All I know is that it worked for my app.
Chris Long
@Dave, your edits prompted me to look over my app's code. I realize that my issue was subclassing, not categories. Sorry about that! If you ever have a problem with subclassing, though, there you go. :)
Chris Long
@Chris aha, that makes sense. Yes, I totally agree. Don't ever subclass `NSArray`. That's asking for a world of hurt. =)
Dave DeLong
Thanks for the update. I switched to use a class method on a SortUtil class for now. If I go back and figure out the other issue, I will post about what I was doing wrong.
Tony Eichelberger