Swift's canImport analogue in Objective-C - 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
}

Related

Macro to detect availability of class properties in 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.

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

How to determine if modules are supported in Xcode?

When I enable the -Weverything custom compiler flag and modules are supported in Xcode, it tells me to switch to using modules - so I change this type of thing:
#import <Foundation/Foundation.h>
to this:
#import Foundation;
...and everything is fine until someone later imports one of my classes into their legacy projects that do not have modules enabled, at which point they have to revert the #import to a #import.
My question is this: Is it possible to wrap these in some sort of preprocessor macro to pick out the correct one at compile time?
Example of what I'm hoping for:
#ifdef MODULES_SUPPORTED
#import Foundation;
#else
#import <Foundation/Foundation.h>
#endif
Thanks
Jase
This is an old question, but needed to know how to do this too. Here is a way to do it:
#ifdef __has_feature(modules)
#import Foundation;
#else
#import <Foundation/Foundation.h>
#endif
Reference: CLANG LANGUAGE EXTENSIONS

Error message "could not build module 'Foundation'"

I searched for this question and could not find much help.
Error:
could not build module 'Foundation'
#import <Foundation/Foundation.h>
What is the problem?
I was able to solve this using the solution provided in this Apple Support Communities thread:
The real problem here is at Build Settings in the session: Apple LLVM 5.0 - Language - Modules, we should set Enable Modules (C and Objective C) to NO
The suggested fix to set Enable Modules (C and Objective-C) did not solve this issue for me.
What did is renaming my someFile.c files to someFile.m. Even though those files contain just C functions (that do use Foundation types), naming them .c produces this error.
I found that if you use some external C / C++ code in your project, you have to remove all the #import in the prefix. That's quite a headache, but it's a true problem.
Cmd + Option + Shift + K and then Cmd + Option + K solved above error for me.
In my case I had a Precompiled Header where I had includes that included <Foundation/Foundation.h> The solution for me was to wrap the include in a
#ifdef __OBJC__
#include SomeIncludeWithFoundation.h
#endif
You may also see in your .pch files something like:
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
Be sure your modules are included in the right place in your Precompiled Header
None of the given solutions worked for me.
I have a project with mixed source codes (C and Objective-C) and the problem was given by a .c which included a shared .h which in turn included the Foundation header:
#import <Foundation/Foundation.h>
In order to solve the problem I had to perform the following steps:
In the .c that was causing the problem add as first include/import statement: #import <Foundation/Foundation.h> You can keep the same import statement in the shared header if you need.
In the project settings select the entry under Targets then click
on Build Phases -> Compile Sources. In the Compiler Flags
add -x objective-c. This will force the compilation of the C source code as Objective-C to allow the linking with the Foundation framework and since Objective-C can embed C source code this is perfectly legal.
In the project settings select the entry under Targets then click on Build Phases -> Link Binary With Libraries. Add the Foundation.framework library in the list.
You can try this:
In your .pch file, write like this:
#ifndef PureStandard_PrefixHeader_pch
#define PureStandard_PrefixHeader_pch
#ifdef __OBJC__
#import "A.h"
#import "B.h"
#endif
#endif
I have resolved by change Build System to Legacy Build System
Open the ios/PROJECT_NAME.workspace file
Then in the top menu, select File → Workspace Settings
Then change Build System to Legacy Build System
From this answer:
Set Allow Non-modular Includes in Framework Modules to YES in target's Build Settings
I was seeing the issue on this line in a .m file that is being built as part of an extension:
#import <Foundation/Foundation.h>
So I had the same problem, but the errors would for some reason not cause the build to fail, so they were like fake errors, and I made them go away by quitting Xcode, and deleting ~/Library/Developer/Xcode/DerivedData/ProjectName
Just rename your Objective-C++ file from *.c to *.mm.
The errors are gone that way. It handles all the imports just fine this way.
Use the following:
Cmd + Alt + Shift + K and then Cmd + Alt + K
Menu File → Workspace Settings → Legacy Build System
Cmd + B
It works for me.

strnlen not declared in this scope on iOS 4.2.1

I have code that was using strnlen in a .mm file
The compiler when using Xcode 4.2 will work just fine to build.
Xcode 3.2.5 however cannot find strnlen()...
I have tried the solutions posted for strlen
#include <cstring> // doesn't work
using std::strlen; // doesn't work
#include <string> // doesn't work
Is there a way to use strnlen on iOS 4.2.1?
For now i'm just converting to NSString object and using length.
Is there something wrong with using strlen, which is a standard C function? I looked up strnlen and it seems to be a GNU extension.