I have an iOS Application that I am managing that has two targets.
This was done as both targets utilize 90% of the same code.
Each target has a specific Preprocessor Macro assigned to so blocks of code can be distinguished for each Target.
Everything compiles correct for both targets.
The problem though is that the xcode only auto compeletes and syntax highlights for the first taget.
For Example:
Target => "MainTarget" - Preprocessor Macro => TARGET_A=1
Target => "OtherTarget" - Preprocessor Macro => TARGET_B=1
Then if I have the following code:
#if TARGET_B
NSLog(#"Log Something %f", 3.5);
#else
NSLog(#"Log other stuff %i", 4);
#endif
Only NSlog(#"Log other stuff %i", 4); is correctly colored.
Compiling and Running works fine, but I'd like to visually know before building and launching that I have a typo.
As such it would be nice to be able to switch weither MainTarget or OtherTarget is the active code for the editor.
It seems that XCode no longer has that feature. Try changing the scheme next to the Stop button.
Source: Where is "Edit Active Target" in Xcode 4
Related
This question already has answers here:
#ifdef replacement in the Swift language
(18 answers)
Closed last month.
from the reference How to handle multiple targets in XCode using swift language? and https://www.appcoda.com/using-xcode-targets/
I have created three targets, each target having different bundle ids and app icons. I have also added different flag to the "Other swift flags" - > Custom swift flag section
like
for first target I added "-DGOLD" ,
for second target I added "-DSILVER" and for
third target I added "-DPLATINUM".
In the AppDelegate I wrote a code
#if GOLD
print ("Gold")
#elseif SILVER
print ("Silver")
#else
print ("Platinum")
#endif
FYI, I am using Xcode 8.3
I tried to run the first target, I always getting "Platinum". Please provide me how to get the flags correctly
I am working with Xcode 9.
I am having same problem and looked for an answer for a few hours and finally found the solution.
At each Target, Build Settings -> Other Swift Flags, I added the wanted flag like this:
Target1 -> -DTARGET1
Target2 -> -DTARGET2
Then in my code used:
#if TARGET1
//
#elseif TARGET2
//
#endif
I am trying to change an image for the two different versions of my app. Here is the code that i have tried so far.
- (void)viewDidLoad
{
[super viewDidLoad];
#ifdef LITE_VERSION
setImage:[UIImage imageNamed: #"30 Tap Game Logo Lite.png"];
#endif
}
You will need to configure your targets' Preprocessor Macros. If you select your target in Xcode and select Build Settings, then search for "preprocessor macros" you'll find the setting you need.
In your light version target (and only in that target) you'll need to add a macro like "LITE_VERSION=1". Then when you build the light version target LITE_VERSION will be defined.
You might also consider using #if LITE_VERSION instead of #ifdef LITE_VERSION just in case you ever want to explicitly turn off LITE_VERSION with #define LITE_VERSION=0.
If you're not sure whether or not your preprocessor macros were set up correctly, you can do something like this:
#ifdef LITE_VERSION
#error Light version is defined.
#else
#error Light version is not defined!
#endif
That will cause the preprocessor to generate an error clearly showing whether or not your macro is defined. (It will also stop the build process, so you can't leave that snippet in your code, but it might help you debug your target configurations.)
Before swift I would define a set of schemes for alpha, beta, and distribution builds. Each of these schemes would have a set of macros that were defined to gate certain behaviors at the project level. The simplest example is the DEBUG=1 macro that is defined by default for all Xcode projects in the default scheme for the Run build. One could query #ifdef DEBUG ... and make decisions in the code accordingly, even compiling out non-necessary code.
It seems that this type of configurational gating is not as easy using swift, as macros are not supported. Can someone suggest a comparable approach, I don't care if the code is compiled out, per se. I would like to gate features based on build scheme, though.
In Swift you can still use the "#if/#else/#endif" preprocessor macros (although more constrained), as per Apple docs. Here's an example:
#if DEBUG
let a = 2
#else
let a = 3
#endif
Now, you must set the "DEBUG" symbol elsewhere, though. Set it in the "Swift Compiler - Custom Flags" section, "Other Swift Flags" line. You add the DEBUG symbol with the -D DEBUG entry.
(Build Settings -> Swift Compiler - Custom Flags)
As usual, you can set a different value when in Debug or when in Release.
I tested it in real code; it doesn't seem to be recognized in a playground.
We ran into an issue with not wanting to set swift compiler flags because we didn't want to have to set them and keep them up to date for different targets etc. Also, in our mixed codebase, we didn't want to make remember to set our flags appropriately all the time for each language.
For ours, we declared a file in ObjC
PreProcessorMacros.h
extern BOOL const DEBUG_BUILD;
In the .m
PreProcessorMacros.m
#ifdef DEBUG
BOOL const DEBUG_BUILD = YES;
#else
BOOL const DEBUG_BUILD = NO;
#endif
Then, in your Objective-C Bridging Header
#import "PreProcessorMacros.h"
Now, use this in your Swift codebase
if DEBUG_BUILD {
println("debug")
} else {
println("release")
}
This is definitely a workaround, but it solved our problem so I posted it here in the hopes that it will help. It is not meant to suggest that the existing answers are invalid.
More swifty solution to Logans method. Set -D DEBUG in Other Swift Flags of Swift Compiler - Custom Flags section in build settings of your target.
Then declare following method in global scope:
#if DEBUG
let isDebugMode = true
#else
let isDebugMode = false
#endif
Now use it as
if isDebugMode {
// Do debug stuff
}
For me, set the debug item of "Active Compilation Condition" to "DEBUG" worked.
Then using DEBGU key work in #IF DEBUG works in debug mode and #ELSE in release mode:
Select your target,
In Build Setting tab search for "Active Compilation Condition",
Set the value of its "Debug" item to "YourKeyWord",
Use simply as follow:
#if DEBUG
print("You'r running in DEBUG mode!")
#else
print("You'r running in RELEASE mode!")
#endif
Swift compiler directives
You can use next compiler directive
#if <some_key>
//logic 1
#else
//logic 2
#endif
//pre Xcode v8
Other Swift Flags(OTHER_SWIFT_FLAGS) = -D <some_key>
-D DEBUG
//from Xcode v8
Active Compilation Conditions(SWIFT_ACTIVE_COMPILATION_CONDITIONS) = <some_key>
DEBUG
I'm working in a mixed language code base where the obj-c code uses a macro to send debug messages to the console (and that macro relies on our debug preprocessor flag). I wanted to be able to call that same macro in the swift code...
I created a class method on one of my obj-c classes that is a wrapper around that macro.
I added that obj-c header to our bridge header file.
Now my swift code calls that class method as a "proxy" to the obj-c macro.
It's mildly annoying that I can't just call the macro straight up in the swift code, but at least now I only have one place in the project to worry about turning my debug flag on/off.
I am building a project that will eventually be compiled to make 4 slightly different applications. The main change I have to make are image changes, but I also want to change a few UILabels as well.
I know that I could create multiple XIB files and modify them to be attached to each target, but I would is there a way to use a macro #define if to detect the name of the target?
Example: Project: Project1
Targets: TargetA, TargetB
#define if Target = TargetA{
label.text = #"This is targetA";
}
Is this possible?
Thanks!
I found an easy way to do this... you can access the bundle identifier which is unique for each target:
NSLog(#"%#", [[NSBundle mainBundle] bundleIdentifier]);
C preprocess macro will accomplish this feature.
In Xcode:
TARGET->Build Settings->Preprocess Marcos
And your source code:
#if DEBUG
// debug build
#else
// release build
#endif
This is already defined macro. You can define your own macros in all project targets.
I often saw "assert " in iOS code, I google it, and got to know it assert true or false.
I want to know if this will auto disable in release mode?
Update: Verified this works in Xcode 8 as well.
In Xcode 7, go into the project build settings and search for "Assert" in the search bar. This shows section "Apple LLVM 7.0 - Preprocessing" section. There is a setting named "Enable Foundation Assertions".
I have successfully enabled/disabled NSAssert from there.
Use NSAssert() and its companions.
in the project define NS_BLOCK_ASSERTIONS for your release configuration.
Xcode 4 tremplates disable NSAsserts in the release configuration. It adds
-DNS_BLOCK_ASSERTIONS=1
to "Other C Flags" for "Release".
From the documentation:
Assertions are disabled if the preprocessor macro NS_BLOCK_ASSERTIONS is defined.
The NSAssert macro evaluates the condition and serves as a front end to the assertion handler.
Each thread has its own assertion handler, which is an object of class NSAssertionHandler. When invoked, an assertion handler prints an error message that includes the method and class names (or the function name). It then raises an NSInternalInconsistencyException exception. If condition evaluates to NO, the macro invokes handleFailureInMethod:object:file:lineNumber:description: on the assertion handler for the current thread, passing desc as the description string.
This macro should be used only within Objective-C methods.
I will here provide a meta-answer:
Both #CocoaFu and #dasblinkenlight are correct. NS_BLOCK_ASSERTIONS turns off NSAssert() and NDEBUG turns off assert(). You need both if you use both.
As Zaph said -DNS_BLOCK_ASSERTIONS=1 is set for release. However, if you wanted to check this.
First observe in the docs that NSAssert is disabled by the macro NS_BLOCK_ASSERTIONS. Then add this to the build and observe it complies ok:
#ifdef NS_BLOCK_ASSERTIONS
#error Error - NS_BLOCK_ASSERTIONS is defined
#endif
Then change the scheme to release (cmd - shift - <)
Then observe that the build fails. Therefore NS_BLOCK_ASSERTIONS is defined meaning NSAsserts are disabled.
Asserts are conditionally compiled out of your code when NDEBUG is defined. If you define NDEBUG=1 in the corresponding build settings section, you will deactivate asserts in your code regardless of the release or debug mode.
Here's what I do at the top of my main():
#if defined(NDEBUG)
{
// The assertion code below should be compiled out of existence in a release
// build. Log an error and abort the program if it is not.
bool ok = true;
NSCAssert(ok = false, #"NS assertions should be disabled but are not");
if (!ok)
{
NSLog(#"Detected release build but NS_BLOCK_ASSERTIONS is not defined");
return -1;
}
}
#endif
Note that since main() is a C function and not an Objective-C function, NSCAssert is used above rather than NSAssert. (NSAssert expects self to be valid.)
Now, as of Xcode 6, the setting is ENABLE_NS_ASSERTIONS, which is set to 1 for Debug configurations and 0 for Release, by default.
You can opt into it for Release builds on the command line by passing the ENABLE_NS_ASSERTIONS=1 argument, which I'm doing for running unit tests that check for assertion conditions, but otherwise should run with the DEBUG flag off.