Macro to detect availability of class properties in Objective-C - objective-c

Xcode 8 introduces Objective-C class properties and I would like to add one to an Objective-C library.
However I would like the library to still compile with Xcode 7. Is there an availability check I can do at compile time?
Something like
#if __hasFeature(objc_class_properties)
#property (class, readonly, nonatomic) MySingletonClass *shared;
#endif
What does work is:
#if __clang_major__ >= 8
…but I'd like to check for feature availability rather than CLANG version.

Searching the LLVM source code I found:
#if __has_feature(objc_class_property)
…which works perfectly.

Related

Swift's canImport analogue in Objective-C

Swift 4.2 has a special condition canImport that helps developers to check whether a module can be imported in project. It was introduced in Swift 4.1.
Now I am working on iOS project written in Objective-C. I use modules, and for each target these modules are different. That's why I want to use something like that:
#if canImport(SomeModule)
#import SomeModule;
#endif
How can I solve this problem? Now I use different "Other C Flags" for each target, but I want to find more flexible solution.
This is a little late as an answer, but i came across this issue while working on a similar case.
I used the __has_include(<SomeModule/SomeModule.h>)
Importing your framework:
#if __has_include(<SomeModule/SomeModule.h>)
#import <SomeModule/SomeModule.h>
#define __HAS_SOME_MODULE_FRAMEWORK__
#endif
Later in your code :
- (void)doSomething {
#ifdef __HAS_SOME_MODULE_FRAMEWORK__
// with SomeModule framework
#else
// without SomeModule framework
#endif
}

Calling obj-c enum from swift not working after upgrading to Xcode 7.3 swift 2.2

The code was working well before the upgrade to Xcode 7.3 from 7.1 and swift 2.2. I have also seen answers using the typedef NS_ENUM(NSUInteger, MyStatus)... but if possible, I prefer not to change the existing obj-c code.
Defined in obj-c header file:
typedef enum {
StatusPending,
StatusTimeout,
StatusSuccess,
StatusFail
} MyStatus;
Statement in Swift file:
/* some code to retrieve the status */
switch (status) {
case .StatusSuccess:
/* do something */
/* other test cases omitted here */
default:
}
I've tried using .rawValue, .value, etc, but I still get an error:
Enum case 'StatusSuccess' not found in type 'MyStatus'
All was working fine before the upgrade and have tried uninstalling/reinstalling Xcode 7.3, Product->Clean, Product->Clean Build Folder.. but without success :-(
You can't declare "typedef NS_ENUM (NSUInteger, EnumName){}" within #interface and #end, the parsing of xcode 7.2 is different from xcode 7.3. So, just move your enum declarations outside #interface #end block and it should work fine, otherwise its considered a private declaration

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

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

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+

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.