Library preprocessor macros not found in consumer project - ios

I have an old .a library called BULib with a macro NEW_API defined in the GCC_PREPROCESSOR_DEFINITIONS of the library target. This macro is used inside the lib to expose some methods in the headers or not with conditional compiling. For example:
#ifdef NEW_API
+ (nullable NSString *)user;
#endif
The problem appears when using this library inside a project. When I want to use
[BULib user];
I get a compile time error
No known class method for selector 'getUser'
The problem is solved if I add NEW_API in the GCC_PREPROCESSOR_DEFINITIONS of the project, then I can use the symbol and it works as expected.
Maybe I'm misunderstanding the use of the macros between libraries and consumer project but I don't want that behavior.
Why do I have to set the macro in the consumer project if the lib has been compiled correctly with the macro set? If this is not the way to achieve this, what is it?
Thank you so much.

There are several possible solutions:
Add NEW_API in GCC_PREPROCESSOR_DEFINITIONS as you did
Delete #ifdef NEW_API and #end
Use #define NEW_API before importing libs header
Add + (nullable NSString *)user; and other missing methods in BULib's category
Personally I prefer 3rd option.
It will be something like that:
#define NEW_API
#import <bulib.h>

Related

Conditional import in Objective-C

My app is in swift and has some files from other modules in objective-c. App has 2 targets, lets say Target-1 and Target-2. When I build the app, a file called as "Target(number)-Swift.h" is generated in build folder.
I need to import this file into the objective-c class. Since there are 2 targets and the file name depends on target name, I need to do conditional import based on which target I am running. I want something like:
if running Target1
#import "Target1-Swift.h"
endIf
if running Target2
#import "Target2-Swift.h"
endIf
If I directly add #import "Target1-Swift.h" it works fine when I build Target1, but fails when I build Target2. I tried the following:
Code I tried:
#ifdef TARGET1_SWIFT_H
#import "Target1-Swift.h"
#endif
With this I don't see errors on imports, but the I see errors like "Use of undeclared identifier 'class_name'" for the classes declared in "-Swift.h", so looks like "-Swift.h" file it not being imported.
Any idea how can I fix this.
You can use Preprocessor macros for this.
Assign a flag for only one target. And use that flag for a condition to determine which target you're running on.
You can use it in the swift file as follow.

How to access header file declaration without #include

I have an iOS project-ProjectX (not created by me) which is able to access declaration from a .h file without using #include "someHeader.h".
In ProjectX, I could just create an empty File and refer to a declaration in "someHeader.h", which I find perplexing. Example:
#import <Foundation/Foundation.h>
#implementation Empty:NSObject
SOME_TYPE_FROM_SOME_HEADER_H x;
#end
and the compiler automatically knows where the definition is?!
I have since tried to create an identical project, duplicating all the project settings, adding static libraries/files, etc. but to no avail.
Any ideas on what I might have missed out or what do I need to configure in the project to achieve this?
As mentioned by Rishab, I was missing a precompiled header (.pch) file. In the project, a pch imported a static library which contained the header file. Therefore, I was able to call the definitions directly.

Is it possible to enable non-arc files without adding "fno-objc-arc" in compile sources of Build Phases?

Is it possible to somehow handle the non-arc files without adding fno-objc-arc to the compile sources in the build phases? More specifically, is there any way to add fno-objc-arc somewhere in the code? The reason is, I want to open source one of my library which uses non-arc files and I don't want people who use my library to manually add fno-objc-arc. Just drag and drop...
No. But if you look at what some libraries do, they write macros that will conditionally call the MRC calls, e.g., release, autorelease, etc., depending upon whether the user is compiling with ARC or not, e.g. using the __has_feature(objc_arc) test. The code then uses these macros, rather than the standard release, retain, autorelease calls. With careful implementation, you can then have a single codebase support both ARC and MRC.
For example, look at FMDatabase.h of the FMDB library. Effectively, you replace your MRC calls with these macros, and they'll only be conditionally included, depending upon whether the project is using ARC or not.
#if ! __has_feature(objc_arc)
#define FMDBAutorelease(__v) ([__v autorelease]);
#define FMDBReturnAutoreleased FMDBAutorelease
#define FMDBRetain(__v) ([__v retain]);
#define FMDBReturnRetained FMDBRetain
#define FMDBRelease(__v) ([__v release]);
#else
// -fobjc-arc
#define FMDBAutorelease(__v)
#define FMDBReturnAutoreleased(__v) (__v)
#define FMDBRetain(__v)
#define FMDBReturnRetained(__v) (__v)
#define FMDBRelease(__v)
#endif

#import with defined prefix (possibly the product name)

Can I import a file with a pre-defined prefix.
e.g. something like this (pseudo code)
#import PRODUCT_NAME+"-Config.h"
I want to have different targets in Xcode for my application. Each target can have its own configuration file(s). I want this to be automatic however, so if the PRODUCT_NAME bit can be the actual target product name that would be the best way.
Thanks for any help you can give me.
Many thanks.
Setup each target with a unique flag under the Other C Flags build setting. Then you can do something like:
#if defined(TARGET1)
#import "Target1Config.h"
#elif defined(TARGET2)
#import "Target2Config.h"
#endif
where TARGET1 and TARGET2 are each defined only for the corresponding target's build settings.
Just give the config files the exact same name, but locate them in different folders. Make sure that each config file only has the appropriate target ticked. Then you can just do #import "Config.h", and the relevant Config.h will be used each time.

#define in header files in Objective-C

I have a Global.h that looks like
#define NUMBERX 21
In AppDelegate.h I include the Global.h file. In the AppDelegate.m I include the AppDelegate.h file. But in the AppDelegate.m I can't access the NUMBERX variable.
ERROR: Use of undeclared indentifier 'NUMBERX'.
If I define NUMBERX in AppDelegate.h than it works, but I want include only the header file (Global.h) in all other header files where I want to use the NUMBERX variable.
How can I solve that?
If you're using objective-c standard #import to include your header file, try replacing it with a "c" #include.
This should be fine, assuming you're not #undefing it before you're using it. Are you using the symbol before you include AppDelegate.h in the AppDelegate.m file? Are you using include guards that might prohibit it's inclusion?
You have to include your Global.h file in AppDelegate.m file.
Could you not use int const NUMBERX then you will get code completion and compiler checking.
Apple has some pretty good guidelines on defining constants and naming them here
Apple Coding Guidelines - Constants

Resources