Exclude class in target if Macro is set to 1 - ios

I defined a preprocessor macro like:
#define ENABLE_SPECIAL_FEATURES 1
So now I am able to include or exclude Code snippets from beeing in the target or not. But I want to have a possibility to do the same with a complete class. So if the macro is set to "1", the class should be included or not.
Is that possible?
UPDATE:
Is the same mechanism possible with frameworks?!

Simply wrap the entire class declaration (.h file) and definition (.m) within that macro value
YourClass.h:
#if ENABLE_SPECIAL_FEATURES
#import <Whatever.h>
#interface YourClass : NSObject
....
#end
#endif // ENABLE_SPECIAL_FEATURES
YourClass.m:
#if ENABLE_SPECIAL_FEATURES
#import "YourClass.h"
#implementation YourClass
....
#end
#endif // ENABLE_SPECIAL_FEATURES
This way you won't even see the class despite the header and implementation file being compiled into the project.

Related

#import ProjectName-Swift.h into header file Can't use swift as .h property?

So I'm trying to use an #objc swift class as a property on my objective-c header file.
example
#objc class SwiftClass: NSObject {
}
#interface ObjcObject : NSObject
#pragma mark - Public Properties -
#property (nonatomic, weak) SwiftClass* swiftClass;
However if I #import ProjectName-Swift.h it gives me the error that "'ProjectName-Swift.h'file not found'
I found an answer here that implies you can't actually import Swift into a header file https://stackoverflow.com/a/29951314/3877767
How then am I supposed to use swift code together with objc code? I would not call swift and objc interoperable if you can't use #objc marked swift classes as properties on and objc header file
So inside of my App-Bridging-Header.h
#import "ObjcClass.h"
and inside of my ObjcClass.h
#import "ProjectName-Swift.h"
This gives the error ProjectName-Swift.h can't find file
Either removing the #import ProjectName-Swift.h, or the #import ObjcClass.hfixes the problem, but then I can't use the Swift/OBJC code respectively
You don't import the header file. You give it to the compiler as a so-called "bridging header" that tells the compiler what to share between the two language environments.
You need to put your header file under the Objective-C Bridging Header as shown below:

Calling Obj-C method from C

I've got a library written in C, where I need to push a call to a method written in Obj-c.
I don't want to modify the original code too much, so I decided to create a "bridge" class to handle the calls between C and ObjC:
DRMBridge.h
#ifndef DRMBridge_h
#define DRMBridge_h
#include "DRMBridgeObjC.h"
void bridge_test();
#endif
DRMBridge.c
#import "DRMBridge.h"
void bridge_test() {
ctest();
}
Above is compiled as C
Now here's my objc code:
DRMBridgeObjC.h
#ifndef DRMBridgeObjC_h
#define DRMBridgeObjC_h
#import <Foundation/Foundation.h>
#interface DRMBridgeObjC : NSObject
+(void) test;
#end
void ctest();
#endif
DRMBridgeObjC.m
#import "DRMBridgeObjC.h"
#implementation DRMBridgeObjC : NSObject
+(void) test {
NSLog(#"OH YEAH!");
}
#end
void ctest() {
[DRMBridgeObjC test];
}
Quite simple.
In the C library I want to call my code from I've added:
#include "DRMBridge.h"
into the .h file and
bridge_test();
in .c file.
Now the best part, when I compile I get:
In file included from /Users/krystian/projects/mdb-reader-lib/reader-Include/ios/MDBReader/Class/DRM/DRMBridge.c:5:
In file included from /Users/krystian/projects/mdb-reader-lib/reader-Include/ios/MDBReader/Class/DRM/DRMBridge.h:8:
In file included from /Users/krystian/projects/mdb-reader-lib/reader-Include/ios/MDBReader/Class/DRM/DRMBridgeObjC.h:12:
In file included from /Applications/Xcode64.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.4.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:8:
/Applications/Xcode64.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.4.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:400:1: error: expected identifier or '('
#class NSString, Protocol;
^
[...]
I went looking, and found this: ios - Parse Issues in NSObjCRuntime, NSZone, and NSObject
However my pch file looks like this:
#import <Availability.h>
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif
I think the issue I have is that the C compiler tries to compile my ObjC file first, instead of the other way around.
I've tried changing the order of files inside Compile Sources to make sure that my .m file is above .c file, but still no go.
Something else I have found which made me lost:
when I follow this answer: https://stackoverflow.com/a/20461780/487605 and change the library itself to .m, and call [DRMBridgeObjC test] code from there - it works.... Compiles fine, no errors given, works fine.
This implies to me, that there's something screwed up with my DRMBridge, but what?
Thanks
Krystian
You've seen the solution already. Use #ifdef __ OBJC__ in your Objective-C header file so that only the plain C bits are compiled when including the file from C
DRMBridge.h
#ifndef DRMBridge_h
#define DRMBridge_h
#include <CoreFoundation/CoreFoundation.h> //or put in .pch
CF_EXPORT void bridge_test();
#endif
DRMBridge.m
#import "DRMBridge.h"
#import "DRMBridgeObjC.h"
void bridge_test() {
ctest(); //or [DRMBridgeObjC test]; if you like
}
Thats all. And you can include DRMBridge.h in whatever you like: in .c, in .m, in .cpp.

Preventing duplicate entry messages

I have two classes that are pretty much identical but one is made for OS X and the other one is made for iOS. Then I have a header file like this:
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
#import "ClassForOSX.h"
#else
#import "ClassForIOS.h"
#endif
The problem is because both classes are included in the project, xcode compiles both and I have a lot of duplicate entries on the errors, because methods have the same name on both classes.
Is there a way to prevent a class from compiling, even if it is included on the project, unless the class is meant for the target?
Yes I know I can include/exclude classes from targets but I am dealing with hundreds of classes in both sides and multiple targets and that would generate a lot of include/exclude operations that will eventually go wrong. I was wondering if there is some solution in code that can just allow a class to compile if the target is right.
Use targets is best for your case. But You can do it in code
note add or remove __MAC_OS_X_VERSION_MIN_REQUIRED at Preprocessor Macros at target->Build Settings
ClassForIOS.h file
#ifndef __MAC_OS_X_VERSION_MIN_REQUIRED
#import <Foundation/Foundation.h>
#interface ClassForIOS : NSObject
// interface
#end
#endif
ClassForIOS.m file
#ifndef __MAC_OS_X_VERSION_MIN_REQUIRED
#import "ClassForIOS.h"
#implementation ClassForIOS
// implementation code
#end
#endif
ClassForOSX.h file
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
#import <Foundation/Foundation.h>
#interface ClassForOSX : NSObject
// interface
#end
#endif
ClassForOSX.m file
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
#import "ClassForOSX.h"
#implementation ClassForOSX
// implementation code
#end
#endif

How to conditionally conform to delegate protocol?

If I am including frameworks in my iOS project that are only available in (for example) iOS 9, but I am still supporting iOS 8, how do I conditionally conform to a delegate protocol depending on the iOS version? For example, I understand I can include the framework conditionally like this:
#import <Availability.h>
#ifdef __IPHONE_9_0
#import <Something/Something.h>
#endif
But what if that framework also needs to conform to a delegate protocol?
#interface ExampleController () <UITextViewDelegate, SomethingDelegate>
How do I only include "SomethingDelegate" if I'm on iOS 9?
Thanks!
Well, in roughly the same manner:
#interface ExampleController () <UITextViewDelegate
#ifdef __IPHONE_9_0
, SomethingDelegate
#endif
>
By the way, this is not the way you should check if the device is running iOS 9 - this only checks if your Xcode supports iOS 9.
The answer of #Glorfindel is more clean, and I would support it, but just to have an alternative answer.
#ifdef __IPHONE_9_0
#import <Something/Something.h>
#define DELEGATES UITextViewDelegate, SomethingDelegate
#else
#define DELEGATES UITextViewDelegate
#endif
#interface ExampleController : UIViewController <DELEGATES>
And there is also a question, what are you going to do with methods belonging to SomethingDelegate protocol, also #ifdef/#endif or just keep them "as is", as they never be called.
This is a good task for a category, with its own files. The contents of those files can be entirely ifdefd out.
//ExampleController+SomethingDelegate.h
#ifdef __IPHONE_9_0
#import <Something/Something.h>
#interface ExampleController (SomethingDelegate) <SomethingDelegate>
#end
#endif
//ExampleController+SomethingDelegate.m
#import "ExampleController+SomethingDelegate.h"
#ifdef __IPHONE_9_0
#implementation ExampleController (SomethingDelegate) <SomethingDelegate>
- (BOOL)somethingShouldMakePancakes:(Something *)something;
#end
#endif
This reads much better than splitting the declaration across multiple lines with a macro in the middle, and keeps all the relevant methods in one place, under one ifdef.

typedef in header file not getting picked up by xcode

I have a typedef in A.h file, and I import that A.h file in B.h that makes use of the same typedef.
For the longest time everything worked fine, but now it breaks complaining that it doesn't recognize the typedef and gives "Expect type" error in xcode, even tho xcode highlights the typedef in the second file, meaning that it knows they are defined else where.
if I manually redefine that typedef then the error goes away. but I get a warning that I am redefining a typedef and that it is a C11 feature.
I tried deleting the derived data, but the error stays. It looks like xcode is trying to look up the typedef before inserting the import files. Any clue? I'm using xcode 4.6
//WebService.h
#import <Foundation/Foundation.h>
#import "AppDelegate.h"
#interface WebService : NSObject
typedef void(^loginUserWithUserNameandPaswordCompletion)(NSDictionary *, NSError*);
+(void)createUserWithName:(NSString*)name
andEmail:(NSString*)email
andPassword:(NSString*)password
onCompletion:(loginUserWithUserNameandPaswordCompletion) complete;
#end
//DataCenter.h
#import <Foundation/Foundation.h>
#import "WebService.h"
#import "AppDelegate.h"
typedef void(^loginUserWithUserNameandPaswordCompletion)(NSDictionary *, NSError*);
#interface DataCenter : NSObject
+(void) logInUserWithEmail:(NSString*) email
andPassword:(NSString*)password
onCompletion:(loginUserWithUserNameandPaswordCompletion)complete;
#end
Try putting typedef before your #interface in WebService.h.
used #class as mentioned by gberginc

Resources