How to enable the new Objective-C object literals on iOS? - objective-c

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.

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:
Peter Steinberger, Using Subscripting With Xcode 4.4 and iOS 4.3+

Related

Generic classes in "frameworkname"-Swift.h causes "Type name requires a specifier or qualifier" error in Xcode 6.3

I updated to Xcode 6.3, and I had two separate projects (one is a framework) in my workspace. Now, Xcode autogenerated this "frameworkname"-Swift.h header file, but when I had a generic class as a property, it produces the following lines:
#class Presentation;
SWIFT_CLASS("_TtC13BusinessLogic31MeetupDetailViewControllerModel")
#interface MeetupDetailViewControllerModel : NSObject
#property (nonatomic) /* RsvpStore<Rsvp> */ anRsvpStore;
#end
There is no equialent to gerenics in Objective-c, so how can I solve this problem?
I found that I can solve the problem if I set the type to NSObject like:
#property (nonatomic) NSObject * __nonnull anRsvpStore;
but with every build, this file is recreated to the same wrong version. So how can I force this build to set the type of this generic to NSObject?
I could stop creating this compatibility header by setting in Build Settings -> Swift Compiler - Code Generation -> Intall Objective-C Compatibility Header to No.
Since I've not written Objective-C code in my project, there is no problem with this option, but this is rather a workaround than a solution for generics in the compatibility header.
Another workaround is if you mark your properties with private, then they won't appear in the compatibility header.
Swift 2.0 update
A new
#nonobjc
attribute is introduced to selectively suppress ObjC export for instance members that would
otherwise be
#objc
. (16763754)
Blockquote
Not tested, but this looks like a solution.
I solved in #1873 https://github.com/realm/realm-cocoa/issues/1873
If you don't need to use swift in objc,just set Intall Objective-C Compatibility Header to No.
If you need to use swift in objc,you have to edited the -Swift.h and set it in Objective-C Generated Interface Header Name

Objective-C object subscripting, iOS5, and GCC

I have a library that was compiled against Apple's LLVM 4.2 compiler (Base SDK 6.1). In it there is object subscripting.
Imagine that my library has only one class with one method. That method does this:
NSLog(#"****** preTests");
NSDictionary *dictTest = #{ #1 : #1 };
NSLog(#"Initialized Dictionary");
NSArray *arrayTest = #[ #1, #2, #3 ];
NSLog(#"Initialized Array");
NSLog(#"****** arrayTest[1] = %#", arrayTest[1]); // First use of subscripting
NSLog(#"****** dictTest[#1] = %#", dictTest[#1]);
Now I create a new project and link this library in. In my application delegate, I call this method. I compile this application with the GCC LLVM 4.2 compiler. It compiles and links fine.
This application will run without error on iOS 6+. This application will crash on iOS 5 at the "First use of subscripting" (above).
2013-07-03 09:15:51.050 GCCTest[167:707] -[__NSArrayI objectAtIndexedSubscript:]: unrecognized selector sent to instance 0x381fb0
Compile it with the Apple LLVM 4.2 compiler and it will run normally.
objectAtIndexedSubscript: is a method made publicly available in iOS 6 and it is my understanding that it what the syntactic sugar of myArray[0] gets translated to.
Can someone help me understand why I see a crash with GCC and not Apple with iOS 5? I'm guessing it has to do with some macros somewhere... Could this be made not to crash with GCC without editing the code of my library?
According to the "Objective-C Feature Availability Index", NSArray subscripting requires at least LLVM Compiler 4.0.
Starting with iOS 6, NSArray has a objectAtIndexedSubscript: method. For iOS 5,
this method is supplied by the static Arclite library that is linked into the application
(see e.g. How to enable the new Objective-C object literals on iOS? and the links given in the answer).
But that is a Clang only feature, GCC does not support ARC.
So I do not see how you could use array subscripting if the main application is compiled and linked with GCC.

Weak linking popoverBackgroundViewClass to make it work in <5.0 IOS

Already checked this question: Weak linking UIPopoverBackgroundView
and already read: http://www.marco.org/2010/11/22/supporting-older-versions-of-ios-while-using-new-apis#fnref:1
I have a custom PopoverBackgroundView declared in a .h and implemented in a .m file. Then, in just one file, I instantiate it like this
self.settingsPopover.popoverBackgroundViewClass = [CustomPopoverBackgroundView class];
I´ve tried doing it like marco says in the link above:
if ([UIPopoverBackgroundView class] != nil) {
self.settingsPopover.popoverBackgroundViewClass = [CustomPopoverBackgroundView class];
}
But I get the same launch error when I run in a 4.3 ipad simulator
dyld: Symbol not found: _OBJC_CLASS_$_UIPopoverBackgroundView
My base sdk is IOS 5.1, and my target deployment is 5.1 as well. Im using LLVM compiler 4.0.
Any ideas? Thanks a lot!
Have you tried using respondsToSelector with the relevant UIPopoverController setBackgroundViewClass method? Remember that properties automatically generate setter and getter methods that you can use in addition to the normal property syntax.
The reason why you're still getting linker errors is because you're still trying to call a method on that class, which doesn't exist.
If it's a case that the entire class doesn't exist, Apple recommends using NSClassFromString(#"UIPopoverController") and checking if the returned result is nil.

Xcode does not compile category

I have added a category to my Xcode project using File > New > Category. I noticed that in Xcode the code completion does not work and even if I add garbage to the class the compiler does not complain.
This is my class:
#import "MyClass+Category.h"
#implementation MyClass (Category)
a
sdf
ads
f#asdlkfjhaslfäasdlföjölfasdf
#end
The .m file has the correct target membership and is in the Compile Sources build phase. What is going wrong. I also tried to restart Xcode to no avail.
Well, that's embarassing. I did not have the proper target set so it was my framework that was being compiled instead of the code I was writing.

Xcode can't find headers in given framework

Messing round a little in Xcode, and I was trying to get my app to look at the users music library with the use of MPMediaPickerController.
Following Apples documentation, I added the MediaPlayer.framework to the project, and in my header I've imported , giving me something like this:
#import <GameKit/GameKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface HelloMusic : UIViewController
{
}
So far so simple. Now, as far as I'm aware I should be able to do
MPMediaPickerController *mp = [[MPMediaPickerController alloc] init];
in my main file and set about launching my picker. Unfortunately XCode stubbronly refuses to admit that there is such a thing as an MPMediaPickerController - if I type MP and hit escape to get code complations I am without any of the MPMedia family. Annoyingly Xcode does recognise any MPMovie... class (from the same framework!). If I try and run the app it compiles fine so it must at least recognise the header from the framework, then chunters along until I get to the assignment of MPMediaPickerController, at which point I get an EXC_BAD_ACCESS, with a console output of
Detected an attempt to call a symbol in system libraries that is not present on the iPhone:
pthread_mutexattr_destroy$UNIX2003 called from function _ZN4llvm3sys5MutexC2Eb in image
libLLVMContainer.dylib.
I'm... certain I'm doing something beyond stupid, but I'm stuck nevertheless.
As the class reference states, it's declared in MPMediaPickerController.h. As such, simply adding...
#import <MediaPlayer/MPMediaPickerController.h>
...should solve your problems. :-)