Xcode Objective-c Compile Time Conditional - objective-c

I'm working on an iOS project in xcode and I'd like to include different codes depending on the build scheme. ie: For anything except the Distribution on an iOS Device scheme, I'd like to include a bunch of debug stuff. But for the Distribution on an iOS Device scheme, I don't want to include the debug stuff.
If I can add some sort of conditional code block it will be very helpful as it will eliminate the chance of me forgetting to change the flag manually.
Thanks!

By default when you create a new XCode 4 project it will add DEBUG to your GCC_PREPROCESSOR_DEFINITIONS (Preprocessor Macros) under build settings so you can do the following.
#ifdef DEBUG
//Debug only code here
#endif
If you need more preprocessor definitions add them under GCC_PREPROCESSOR_DEFINITIONS or OTHER_CFLAGS or OTHER_CPLUSPLUSFLAGS [prefix the last 2 with -D] for the correct build configuration.

Related

Xcode cannot find ProductModuleName-Swift.h

I'm attempting to import my "-Swift.h" file into one of my Objective-C .h files but xcode keeps telling me that the file doesn't exist
#import "Aesculus-Swift.h"
If I command click on the file name it will take me to the generated header file so I know it exists. Why is xcode not able to find it?
This seems like just another issue with Xcode and it's complex tool chain of static analysers and compilers.
Openradar lists radar://21362856 - Swift to Objective-C bridging is unreliable. I am sure there are more but I stopped looking after finding one for this example.
The author imarcelv notes in the description:
I asked a Swift engineer at WWDC in a lab and even he didn't know how to fix this issue.
Steps to Reproduce:
Add a ramdom Swift class to an Objective-C project
Add the #import "ModuleName-Swift.h" file that Xcode generates automatically
Try to use it or just try to compile the project
From time to time it simply doesn't work
It's probably best to file a radar on this issue as it seems that others are already calling it out.
One other thing you could try...
Historically, it was possible for Xcode to completely lose it's syntax highlighting and you could always find out what files the static analyser was giving up on by increasing log level of clang.
I'm not sure if it's still relevant but if I was in your position I'd be trying this command:
defaults write com.apple.dt.Xcode IDEIndexingClangInvocationLogLevel 3
This generates logs you can search with using Console.app for just xcode to highlight the messages. You'll want to trash the derived data of your project to force it to re-compile things.
Although not the same issue as what you're seeing, I have had this post on the syntax highlighting issue bookmarked for years for the above defaults write command to try in times like these.
I solved this recently by adding the following entry to my .xcconfig (you could add it in Xcode's Build Settings > User Header Search Paths if you prefer).
USER_HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR)/MyFramework.framework/Headers
This tells the compiler to search for headers in the build output directory, which is where Xcode puts the generated header (at least in the case of this framework).
In my case this is a directory like ~/Library/Developer/Xcode/DerivedData/MyProject-LongCode/Build/Products/Debug-iphonesimulator/MyFramework.framework/Headers/MyFramework. You might find your generated header in there too.
Xcode's header and dependency management is a hot mess, and it's not surprising that it doesn't work for you.
I had trouble with this stuff & found that your -Swift file is the Product name of your Target ( not just the name of your Target ) . I found the details here helpful: http://ericasadun.com/2014/08/21/swift-calling-swift-functions-from-objective-c/
When you encounter such situation, just find your kinda "ProductName-Swift.h" file by just cmnd+click on it (even if xcode shows warning about it is not found, the #import "Aesculus-Swift.h" string is still clickable) and then in opened code editor window choose context menu and "Show in Finder" item, then explicitly add it to your project.

When to use "#if __IPHONE_OS_VERSION_MIN_REQUIRED > x"?

This question addresses how to conditionally include code based on iOS version. But how does it work?
Suppose I set iOS Deployment Target to 3.2 in Xcode 4.5.2. In my code I put in some #ifdef statements:
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
// Some iOS 4+ code
#endif
If I run the code on a 3.2 device, this code won't be there, but if I run it on a 4.3 device, it will, right? How does that happen? Or am I misunderstanding what's going on here?
That is a compile time check so it will create the same behavior on any iOS version. Since the Deployment Target is less than 4.0 the code inside the if statement will not run on any device.
If you want the behavior you described you need to do a runtime check. You can see an example of how to do this in the thread that you linked.

How to create a 2nd app from a 2nd target in XCode?

So I created a simple project, which I can test as an iPhone app. Now I'd like to make a slight variation of it, with an iAd. I was able to duplicate the target and test to the iPhone, by managing schemes (http://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/Building/Building.html).
The issue is that no matter what scheme I test, I overwrite the other app. I'd like to be able to have two apps
AppName
AppName (Free)
living at the same time on my phone.
I want to avoid duplicating source files, because only the storyboard and the view controller are different, they both use the same images and model otherwise.
Any help is welcome!
Have you tried changing the bundle identifier in the new target you just created? So your full version would have bundle identifier: "com.yourcompany.AppName" and your lite version will have a bundle identifier of: "com.youcompany.AppNameLite"
I'm not currently on my Mac partition so sorry if I'm a bit off.
I would add a new configuration for your app. Call it something like "Release Free". Add a gcc preprocessor symbol "FREE" to this configuration.
Then everywhere you initialize and instantiate your iads put the code within some "#if" statements.
Something like this.
#if FREE
// Init iAds
#endif

Change code based on Xcode build type

When I build my app as an Adhoc, I would like to set a specific var to YES. Is it possible for my code to know what it is being built for, and change a part of the code if it is for debug or adhoc?
In the Build Settings for a target you can set preprocessor symbols based on the build type you are doing, then in your code you can test for these using #ifdef/#endif, or to test for specific values you can use #if. Look up the preprocessor in the docs.
For example, this is commonly used to define the symbol DEBUG for debug builds and then conditionally include code:
#ifdef DEBUG
NSLog(#"The value of ix is %d", ix);
#endif

How can I access a user-defined Xcode build setting?

If I added a user-defined setting in my build configuration, how can I read that setting in my Objective-C code?
I have two files in my project, debug.plist and release.plist. I want my MainApp.m file to read one of these files based on which build configuration is running. I set up a user-defined setting named "filename" in both the Debug and Release configurations to point to the appropriate file. But I don't know how my MainApp.m file can read the filename variable from the current running configuration.
Here's what I did, I'm not 100% sure if this is what you're after:
Go into the build Settings panel and choose the gear icon in the bottom left: add User-Defined Setting
Create your user defined setting, for example:
MY_LANG -> en_us
Then, in the Preprocessor Macro's setting, you can reference that value:
LANGCODE="$(MY_LANG)"
Now you can refer to LANGCODE in all your source files, and it will be whatever you filled out in your custom build setting. I realize that there's a level of indirection here, but that is intentional in my case: my XCode project contains a bunch of different targets/configurations with their own preprocessor macro's. I don't want to have to go into all of those, just to change the language code. In fact, I define the language code on the project level. I also use MY_LANG in a couple scripts, so just a preprocessor macro wouldn't do. There may be a smarter way, but this works for me.
You can access your user-defined build setting at run-time (as suggested in a comment by #JWWalker)
Add an entry to your Info.plist file, and set it to your User-defined Build Setting
MySetting -> ${MYSETTING}
Read its value from code
Objective-C
[[NSBundle mainBundle] objectForInfoDictionaryKey:#"MySetting"];
[Edit] Swift
guard let mySetting =
Bundle.main.object(forInfoDictionaryKey: "MySetting") as? String
else { print("MySetting not found") }
Swift 4
Lets say "filename" is the String you need in your app.
Add filename=YOUR_STRING to user-defined setting(for debug and release).
And add filename = $(filename) to info.plist.
Then in Swift code:
if let filename = Bundle.main.infoDictionary?["filename"] as? String {
// do stuff with filename
}
else {
// filename wasn't able to be casted to String
}
Your code can't read arbitrary build settings. You need to use preprocessor macros.
EDIT: For example, in the target settings for the Debug configuration, you could add DEBUGGING=1 in the Preprocessor Macros build setting, and not define DEBUGGING in the Release configuration. Then in your source code you could do things like:
#if DEBUGGING
use this file
#else
use the other one
#endif
I tried zmippie suggestion but it didn't work for me.
I got it working with this:
${MY_LANG}
In case anyone else is still stuck looking for how to do preprocessor macros, look for the Apple LLVM - Preprocessing section in Build Settings. Under it, you will see a section called Preprocessor Macros.
This is where by default, Xcode inserts the DEBUG=1 macro for the debug build configuration.
You can add your own here, and give them different values for debug, release and any custom build configs you may have.
To add one, double-click on the current value list for the config you want, and it'll display a nice little editor with one macro on each line. Just add your own macro name, and give it a value the same way the DEBUG one is done.
These can be checked during the preprocessor build phase using #if, #ifdef etc. to provide conditional code or values.
Hope that helps.