How to enable the new Objective-C object literals on iOS?
Asked Answered
A

1

23

When I create a new project with Xcode 4.4 and add these lines:

NSDictionary *test = @{ @"key" : @"test value" };
NSString *value = test[@"key"];
NSLog(@"value is: %@", value);

it compiles with no warnings and executes as expected.

Adding the same lines to an existing project produces the compiler error:

NSString *value = test[@"key"]; <-- Expected method to read dictionary element not found on object of type 'NSDictionary *'

I compared both projects' target build settings but nothing leapt out at me.

Update: The new project that successfully compiled was for OSX. I tried another new one for iOS with the above lines and it fails to compile, same as my pre-existing (iOS) project.

Australoid answered 25/7, 2012 at 21:9 Comment(9)
And both projects were using clang 4.0?Kippy
@Kippy Both using "Apple LLVM compiler 4.0".Australoid
And both target x86_64 (not i386)?Kippy
Hmm... the one that compiles is targeting OSX (i386 x86_64) and the one that fails iOS (armv6 armv7). Arm LLVM compiler doesn't support the new object literals?Australoid
Yes, it's supposed to work. "All of these new language features require the modern Objective-C runtime. This runtime is used on all architectures for iOS, and 64-bit x86 (x86_64) on the Mac. These features are not supported when targetting i386 on the Mac."Kippy
I just created a fresh iOS project, pasted the above lines in, and it fails to compile.Australoid
I haven't seen any examples on the use of the syntax test[@"key"]. Where did you see that?Kippy
In clang.llvm.org/docs/ObjectiveCLiterals.html, Object Subscripting section.Australoid
The XCode 4.4's what new did mention that these literals only applies to apps on OSX, not iOSPontifex
D
48

This has nothing to do with old vs. new project, but rather is a factor of the SDK you use. The problem you're running into is that while this is a compiler feature, it requires SDK support. The iOS 5 SDK does not provide that support, though the iOS 6 SDK does.

For that reason, now you should just use the iOS 6 SDK. Read on if you want to use object subscripting with the iOS 5 SDK.

All you need to do is add a header file so that the compiler will try the call. There's no need to add an implementation; it's handled automatically by arclite. (If you are not using ARC, you will have to force the linker to include arclite. But you still don't have to actually switch to it.)

Create a new interface file, NSObject+subscripts.h.

#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000
@interface NSDictionary(subscripts)
- (id)objectForKeyedSubscript:(id)key;
@end

@interface NSMutableDictionary(subscripts)
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
@end

@interface NSArray(subscripts)
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
@end

@interface NSMutableArray(subscripts)
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
@end
#endif

I've put this chunk on github.

Note: I used to suggest adding the required methods to NSObject before explaining how to add them only to the relevant objects. In retrospect, I believe this was an error on my part; it led to errors being caught at runtime rather than compile time, unlike the approach now presented here. That approach is still on my blog, but I now believe it to be more of a cool hack than a useful approach.

Source:

Dior answered 25/7, 2012 at 22:52 Comment(10)
That did the job for me, thanks! It'll be fine until Xcode 4.5 ships with the official iOS support.Australoid
I only added it on NSDictionary / NSArray and implemented it to call the regular methods. It works just fine (that's what ios 6 does anyway).Umbilication
You don't need an @implementation. But yeah, today I had no problem adding just the categories I needed to just the classes I wanted. I'll update the answer.Dior
Anyone have any idea how Apple would feel about this in an app submission? As I understand it, ARClite actually adds the necessary implementations itself, so from Apple's point of view the methods objectAtIndexedSubscript: etc are not undocumented private methods but user-defined methods, correct?Eindhoven
Correct. You're making calls to arclite. I haven't gone through App Review yet, but there's no other point to Apple putting those swizzles in arclite than for us to use them.Dior
how to force the linker to include arclite?Horeb
Turn on ARC in the target's build settings.Dior
To clarify, you saying that in order to use literals in a non-arc project, I must turn on arc and put the linker flags on all my files to not use arc? This does not sound efficient.Bobbe
No, just turn on ARC for the linker only. I used to know how to do this, but don't anymore. Sorry. :) I think it might have been OTHER_LDFLAGS.Dior
Also even using a newer SDKs will give you problems on iOS 5 if you try to use subscripting from a class' +(void)load method! It seems that arclite is not yet loaded at that time.Automata

© 2022 - 2024 — McMap. All rights reserved.