I define a simple macro in objective-c header file, and import this header file into Swift through project bridging header. I was able to use this macro as a constant in Swift, but when I use it to do conditional compiling, it doesn't work properly.
I create a simple project in Xcode 10.2.1 and add some code to reproduce it.
In ViewController.h
#define TEST_FLAG 1
#interface ViewController : UIViewController
#end
In ViewController.m
#import "testMacro-Swift.h"
- (void)viewDidLoad {
[super viewDidLoad];
SwiftClass *s = [[SwiftClass alloc] init];
[s printMSG];
#if TEST_FLAG
NSLog(#"Objc works.");
#endif
}
In testMacro-Bridging-Header.h
#import "ViewController.h"
SwiftFile
#objc class SwiftClass: NSObject {
#objc func printMSG() {
print("Macro \(TEST_FLAG)")
#if TEST_FLAG
print("compiled XXXxXXXXX")
#endif
}
}
Console Output
Macro 1
2019-07-03 14:38:07.370231-0700 testMacro[71724:11911063] Objc works.
I expected compiled XXXxXXXXX to be printed after Macro 1, but it not.
I am curious why this will happen.
My project is mixed with objc and swift. I don't want to declare a same flag in swift.
Based on this Apple article, https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_macros_in_swift, simple C (and Objective-C) macros are imported into Swift as global constants. This is demonstrated by the output from your line
print("Macro \(TEST_FLAG)")
The snippet
#if TEST_FLAG
print("compiled XXXxXXXXX")
#endif
uses a different TEST_FLAG, which is a Swift preprocessor flag. You could define it under Build Settings -> Active Compilation Conditions as TEST_FLAG or under Build Settings -> Other Swift Flags as -DTEST_FLAG.
The above explains why this happens. I can't think of a simple way to avoid defining the same flag separately for Objective-C and Swift preprocessor in Xcode. If you just want to control whether some Swift code is executed based on the TEST_FLAG, you can do something like this:
if TEST_FLAG != 0 {
print("compiled XXXxXXXXX")
}
However, if you want to control compilation of the code, then you may have to use separate TEST_FLAGs for Objective-C and Swift and make sure they are consistent. To aid in making them consistent, you could set the TEST_FLAG used by Objective-C code in Other C Flags, which allow you to define different flags for different SDKs, Architectures, and build types (Release/Debug). Active Compilation Conditions allow the same flexibility.
Another trick to facilitate consistency between (Objective-)C and Swift compiler flags is to create a new user-defined build setting: click on + to the left of the search box under Build Settings.
Say, call it COMMON_TEST_FLAG and set its value to TEST_FLAG. Then add -D$(COMMON_TEST_FLAG) to Other C Flags and Other Swift Flags. Now when you build your code TEST_FLAG will be defined in both Objective-C and Swift code within your target. If you don't want it to be defined, just change the value of COMMON_TEST_FLAG to something else. A couple of things to watch for, though:
You cannot make COMMON_TEST_FLAG empty: this will cause the other
flags to be just -D, leading to a build error.
Make sure the value of COMMON_TEST_FLAGdoes not conflict with
macros defined elsewhere.
Swift's preprocessor is (intentionally) waaaaaaay more limited than C's. Macros come with really serious draw backs.
They define regions of code that aren't active in every build target. Because of this, your tests won't be hitting every branch (or even compiling every branch). This quickly becomes a maintenance disaster. For n unique flags, there are 2^npossible sets of values and thus,2^n` possible builds. Do you have to test each of them? Maybe, maybe not, but even just reasoning about what to test isn't easy.
They can get tangled up and incredibly complex, especially with nested blocks.
In general, try to express as much of your code in the main programming language (C, ObjC, Swift), and resort to using macros only when there's a good reason, such as:
Reducing repetition in a way that can't be done with a function.
Improving performance in a critical region of code (by forcing inlining of macro code, e.g. #define max(a, b) ((a) < (b) ? (b) : (a))). Though this is exceptionally rare.
Expressing a piece of logic that can't be expressed in the language. For example, there's no way to express if #available(...) in Swift, without using the preprocessor.
Your example doesn't meet any of these criteria. It's increasing repetition, it's not performance-critical, and it's not doing something that can't be done in regular Swift code.
A much better approach to this (in both Swift and Objective C), is to create a logger that is initialized with different configurations between debug and release builds. Your viewDidLoad method should not concern itself whether or not TEST_FLAG is set. View controllers should control views, not make decisions as to what things should be logged. It should just call the logger to send off whatever log messages it wants to send, and leave it up to the logger to decide how to log those messages (to an output stream, file, in-memory circular buffer, database, stream to an analytics API, ignore them, etc.)
I have a header file that is included by *.c and by *.m sources. When a C source includes the file, I'd like to skip some lines that contain Objective C stuff. Thus, I was wondering if gcc has a builtin compiler define that is active whenever it is compiling an Objective C file, something similar to the __cplusplus define that indicates that the compiler is currently compiling a C++ source. Is there an Objective C equivalent?
Of course, I could just #define my own preprocessor symbol but I'd like to know whether gcc already has an inbuilt definition for this.
To answer my own question, gcc defines the __OBJC__ macro whenever it is compiling an Objective C source.
I just changed my .m files to .mm and use C++. Is there a way to do the same with Swift?
The confusion may come from the assumption that merely changing a file extension from .m to .mm is all you need to bridge the languages, when, in reality, it does nothing of that sort. It is not the .mm that causes friction with .cpp, it is the .h header which must positively not be a C++ header.
Same project: Yes.
In the same project, you can happily mix C, C++, Objective-C, Objective C++, Swift, and even Assembly.
...Bridging-Header.h: you expose C, Objective-C and Objective-C++ to Swift using this bridge
<ProductModuleName>-Swift.h: exposes automatically your Swift classes marked with #objc to Objective-C
.h: this is the tricky part, since they are ambiguously used for all flavors of C, ++ or not, Objective or not. When a .h does not contain a single C++ keyword, like class, it can be added to the ...Bridging-Header.h, and will expose whatever function the corresponding .c or .cpp functionalities it declares. Otherwise, that header must be wrapped in either a pure C or Objective-C API.
Same file: No.
In the same file, you can't mix all 5. In the same source file:
.swift: you can't mix Swift with anything
.m: you can mix Objective-C with C. (#Vinzzz)
.mm: you can mix Objective-C with C++. This bridge is Objective-C++. (#Vinzzz).
.c: pure C
.cpp: you can mix C++ & Assembly (#Vality)
.h: ubiquitous and ambiguous C, C++, Objective-C or Objective-C++, so the answer is it depends.
References
Invoke Assembly from C++ (Brett Hale)
Invoke Swift from Objective-C (Svitlana)
Invoke C, C++, Obj-C, Obj-C++ from Swift (SwiftArchitect, self)
To download a full iOS 9, Xcode 7 project, search for SO-32541268 in Swift Recipes.
No. When you switch from .m to .mm you are actually switching from Objective-C to a different language (which has many subtle differences) called Objective-C++. So you're not really using C++; you're using Objective-C++ which accepts most C++ as input (in the same way that C++ accepts most but not all C as input). When I say it's not quite C++, consider a C++ file that includes a variable named nil (which is legal C++) and then try to compile that as Objective-C++.
Swift doesn't have the same relationship. It is not a superset of C or C++, and you can't directly use either in a .swift file.
"Using Swift with Cocoa and Objective-C" also tells us:
You cannot import C++ code directly into Swift. Instead, create an Objective-C or C wrapper for C++ code.
I wrote a simple Xcode 6 project that show how to mix C++, Objective C and Swift code:
https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console
In particular the example call an Objective C and a C++ function from the Swift.
The key is to create a shared header Project-Bridging-Header.h and put the Objective C headers there.
Please download the project as a complete example.
You can also skip the Objective-C file in between. Just add a C header file with a .cpp source file. Have only C declarations in the header file and include any C++ code in the source file. Then include the C header file in the **-Bridging-Header.h.
The following example returns a pointer to a C++ object (struct Foo) so Swift can store in a COpaquePointer instead of having struct Foo defined in the global space.
Foo.h file (seen by Swift - included in the bridging file)
#ifndef FOO_H
#define FOO_H
// Strictly C code here.
// 'struct Foo' is opaque (the compiler has no info about it except that
// it's a struct we store addresses (pointers) to it.
struct Foo* foo_create();
void foo_destroy(struct Foo* foo);
#endif
Inside source file Foo.cpp (not seen by Swift):
extern "C"
{
#include "Foo.h"
}
#include <vector>
using namespace std;
// C++ code is fine here. Can add methods, constructors, destructors, C++ data members, etc.
struct Foo
{
vector<int> data;
};
struct Foo* foo_create()
{
return new Foo;
}
void foo_destroy(struct Foo* foo)
{
delete foo;
}
I have just made a little example project using Swift, Objective-C and C++. It's a demo of how to use OpenCV stitching in iOS. The OpenCV API is C++ so we can't talk to it directly from Swift. I use a small wrapper class who's implementation file is Objective-C++. The Header file is clean Objective-C, so Swift can talk to this directly. You have to take care not to indirectly import any C++-ish files into the the headers that Swift interacts with.
The project is here: https://github.com/foundry/OpenCVSwiftStitch
Here's my attempt at a clang tool to automate C++/swift communication. You can instanciate C++ classes from swift, inherit from C++ class and even override virtual methods in swift.
It will parse the C++ class you want to export to swift and generate the Objective-C/Objective-C++ bridge automatically.
https://github.com/sandym/swiftpp
Swift is not directly compatible with C++. You can work around the issue by wrapping your C++ code with Objective-C, and using the Objective C wrapper in Swift.
I also have a demo program for swift combining opencv.
You can download it from https://github.com/russj/swift_opencv3_demo.
More information about the demo http://flopalm.com/opencv-with-swift/.
No, not in a single file.
However, you may use C++ in Swift Projects without needing a static library or framework. Like others have said, the key is to make an Objective-C bridging header that #includes C-compatible C++ headers that are marked as C compatible with the extern "C" {} trick.
Video tutorial: https://www.youtube.com/watch?v=0x6JbiphNS4
Other answers are slightly inaccurate. You can actually mix both Swift and [Objective-]C[++] in the same file, though not quite the way you would expect.
This file (c.swift) compiles to a valid executable with both swiftc c.swift and clang -x objective-c c.swift
/* /* */
#if 0
// */
import Foundation
print("Hello from Swift!")
/* /* */
#endif
#include <stdio.h>
int main()
{
puts("Hello from C!");
return 0;
}
// */
One trick (of many) is that
You need a separate header for your bridging obj-c++ file...
You can't just throw #interface and #implementation in the same .mm file as one often does normally.
So in your bridging header file you have
#import "Linkage.hpp"
Linkage.hpp has the #interface for Linkage and Linkage.mm has the #implementation for .mm
And then
...you actually don't #include "yourCpp.hpp" in Linkage.hpp.
You only put #include "yourCpp.hpp" in the Linkage.mm file, not in the Linkage.hpp file.
In many online examples/tutorials, the writer simply puts the #interface and #implementation in the same .mm file, as one often does.
That will work in very simple cpp bridging examples, but,
The problem is:
if your yourCpp.hpp has any c++ features at all which it surely will (like, the first line #include <something>), then the process will fail.
But if you just don't have the #include "yourCpp.hpp" in the Linkage header file (it's fine to have it in the .mm file, obviously you'll need to) - it works.
Again this is unfortunately just one tip in the whole process.
In case this is helpful to anyone, I also have a brief tutorial on calling a simple C++ static library from a trivial Swift command line utility. This is a really bare-bones proof of concept piece of code.
No Objective-C involved, just Swift and C++. Code in a C++ library is called by a C++ wrapper that implements a function with extern "C" linkage. That function is then referenced in the bridging header and called from Swift.
See http://www.swiftprogrammer.info/swift_call_cpp.html
I am providing a link to SE-0038 in the official resource, described as
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.
The status as of today is that this is the feature request which has been accepted but not yet scheduled.
This link is intended to steer anyone looking for this feature in the right direction
I have the source code for a video decoder which is written in C.
The code was successfully compiled and executed on MAC terminal (which uses GCC compiler). Now I'm trying to create an application on Xcode with the same source code. Only the GUI for the application is written in Objective-C.
When I tried to execute on Xcode (which uses LLVM compiler), I'm getting a lot of errors in the C code.
The only other compiler option that Xcode provides is LLVM GCC 4.2. I compiled using that and found that it is not able to recognize the code written in Objective-C.
Is there any compiler that can be used for both Objective-C and C?
Can GCC 4.2 compiler be used for compiling Objective-C code?
How to tell Xcode to compile using GCC 4.2 compiler?
Kindly help. Thanks in advance!
Both LLVM and GCC can be used to compile C, C++ and Objective-C code.
My guess is that some compiler flags are set incorrectly.
Objective-C is a strict superset of ANSI C, so any compiler that can compile Objective-C code can also compile (ANSI) C code. If your library does not use standard C, then you might run into problems.
The same is true for Objective-C++, which is a strict superset of C++.
If, like in your case, you have a conflicting typedef in your header file, you can use conditional compilation to hide the typedef when compiling Objective-C code:
#ifndef __OBJC__
typedef unsigned char BOOL;
#endif
I had this declaration.
- (BOOL)getNHPData:(REMOTE_MESS_ID)msgId withEvent:(RSEvent*&)pEvent;
I tried with RSEvent** also but i'm getting this error for 2 times
Expected ')' before RSEvent
Why is it so.
Objective-C is a superset of the C language and does not have references. If you want to use C++-style references in Objective-C, you must compile as Objective-C++ (as you might expect, Objective-C++ is a superset of C++). Use the .mm extension to automatically use the Objective-C++ in Xcode.
If the method in question is a public API that will be consumed from Objective-C, I would highly recommend using a pointer-to-pointer (RSEvent**) instead of a pointer reference. Using Objective-C++ in a header "infects" clients with Objective-C++ (unless you're very careful). Objective-C++ takes much longer to compile that Objective-C and you will eventually run into the inevitable C vs. C++ incompatibilities. Standard practice is to hide Objective-C++ from public APIs whenever possible.
I personally have never had much success in c++ or obj-c with pointer references, if I need that kind of functionality, I usually just use a pointer pointer like this:
some function()
{
RSEvent *pEvent = new RSEvent();
[self getNHPData:DEFAULT_MSG_ID withEbvent:&pEvent];
}
- (BOOL)getNHPData:(REMOTE_MESS_ID)msgId withEvent:(RSEvent**)pEvent
{
//Do some stuff
}