Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiler error "expected method not found" when using subscript on NSArray

I wrote this simple code to try out the new Objective-C literal syntax for NSArrays:

NSArray *array = @[@"foo"];
NSLog(@"%@", array[0]); 

The first line works fine, but the subscripting results in an error:

Expected method to read array element not found on object of type 'NSArray *'

Just wondering if I have done something wrong, or if the literals haven't been fully implemented yet. I'm compiling with Apple LLVM 4.0 and using the iOS 5 SDK.

Here's a screenshot of the error, too.

Error

like image 255
Ben Trengrove Avatar asked Jul 11 '12 05:07

Ben Trengrove


3 Answers

You've got to be compiling with the iOS 6 or OS X 10.8 SDKs -- otherwise Foundation objects don't have the necessary methods for the subscripting bit of the literal syntax.* Specifically in this case, the subscripting expects objectAtIndexedSubscript: to be implemented by NSArray, and that's a new method that was created to interact with this compiler feature. The parts of the new syntax that just have to do with object creation should work fine, though -- I don't believe that requires any new methods.

Further reading at http://clang.llvm.org/docs/ObjectiveCLiterals.html


*I base this on a bit of research performed by borrrden: https://stackoverflow.com/a/11407844/603977

I've gotten a lot of upvotes on this answer, which I really feel is founded on borrrden's. Please, if you think my answer is worth an upvote, click through and vote there too.

like image 169
jscs Avatar answered Nov 01 '22 03:11

jscs


If you're not targeting iOS 6 or OS X 10.8, I would like to point out that it's still remarkably easy to get subscripting to work. All you have to do is add the required methods as a category the classes you want subscripting to work for, and implement those methods appropriately. So add to the following classes the methods:

NSArray : - (id)objectAtIndexedSubscript: (NSUInteger)index;

NSMutableArray : - (void)setObject: (id)obj atIndexedSubscript: (NSUInteger)index;

NSDictionary : - (id)objectForKeyedSubscript: (id)key;

NSMutableDictionary : - (void)setObject: (id)obj forKeyedSubscript: (id)key;

Implementing this is a simple as calling the appropriate method for the class. For example, to implement subscripting on NSArray you just implement:

- (id) objectAtIndexedSubscript:(NSUInteger)index{
    return [self objectAtIndex:index];
}

The only downside I can see is you need to make sure to import your category into any class that intends on using the subscripting. Of course, you can get around that requirement by including the #import in your prefix header, usually the file: <appname>-Prefix.pch. (thanks Josh Caswell for pointing that out).

One upside is you can alter the subscripting methods to suit your needs. For example, Apple doesn't allow you to add/remove objects to NSMutableArray using subscripting, but this can be accomplished easily enough:

 - (void) setObject:(id)obj atIndexedSubscript:(NSUInteger)index{
    if (index < self.count){
        if (obj)
            [self replaceObjectAtIndex:index withObject:obj];
        else
            [self removeObjectAtIndex:index];
    } else {
        [self addObject:obj];
    }
}
like image 44
Aaron Hayman Avatar answered Nov 01 '22 03:11

Aaron Hayman


I got the following code from this link:

You can just add this category to NSObject and collection subscripting will work. I put it in my .pch file.

// Add support for subscripting to the iOS 5 SDK.
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000
@interface NSObject (SubscriptingSupport)

- (id)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
- (id)objectForKeyedSubscript:(id)key;

@end
#endif

Of course you will need the newest version of CLANG which is already in XCode 4.4.

like image 2
Jeff Wolski Avatar answered Nov 01 '22 04:11

Jeff Wolski