How to bridge Objective-C++ code to Swift when we have C++ classes as parameters in header files? - ios

I'm trying to call C++ methods from Swift, and what I've learnt is that I can wrap the C++ stuff to an Objective-C++ class first, then export this Objective-C++ class to Swift. Here's my code:
// CPPClass.h
class CPPClass {
int data;
};
// OCClass.h
#import "CPPClass.h"
#interface OCClass : NSObject
- (instancetype)initWithCPPObject:(CPPClass &)obj;
#end
// MyProject-Bridging-Header.h
#import "OCClass.h"
When I build the project, the compiler throws an Expected a type error in OCClass.h. If I comment out the header file in MyProject-Bridging-Header.h, everything becomes fine, except that I can't use it in Swift any more.
I can solve it by replacing the specific C++ type parameter with a void * pointer, and in this case I can freely use CPPClass in OCClass.mm file, but I wonder if there's any more elegant solutions?

Related

Can iOS Objective-C app use nested static ObjC/Swift libs?

OBJ-C ONLY...
That is,
An ObjC app imports ObjC static lib A.
Static lib A imports static lib B.
Static lib A has functions that call functions within lib B.
The app only calls functions in lib A and does not call functions in lib B.
Can I assume that lib A or B can be either Obj-C or Swift?
IE. Can an ObjC app import an ObjC-or-Swift static lib A that itself imports a second ObjC-or-Swift static lib B? (yes, 4 use case permutations)
the git repository https://github.com/CombineCppSwiftObjcInStaticLib i created for you is showing this..
your initial #objc func run_central() in BLE_central.swift is exposed, which triggers the precompiler to generate objc compatible headers (bridge) which then again makes it possible to call the function from a method inside .mm(objc++) or .m(objc) when this generated header is imported.
In fact Hub_lib inside the repo is a static ObjC++ lib mixed with Swift. It would work the other way around also. The headers are the key for success here. If you can provide some objc or c or c++ header to swift functions it becomes compatible and wise versa. I mean in general, thats the idea of headers. If you don't have headers, that does not mean you can not call some external stuff, it just means you would call it blind. A proper IDE will complain before you even try to do this evil stuff, unknown entry points aka unknown symbols etc.. So you go for a proper header - always.
To properly combine swift with other languages its good to know there are always two ways of bridging.
In case of Objective-C (and also Objective-C++) it is
Bridging into Swift (projectname-Bridging-Header.h),
and Bridging out of Swift (expose with #objc to trigger automatically internal generation of projectname-Swift.h file. So this header is "invisible" in the file browser on the left side. Nor will you find it in the repo as file, it is named by modulename which is the project-name). The last mentioned header you could even write manually yourself, with lots of troublesome back-draws.
Hint: Executable code is executable code. No matter what language, as far it is compiled for the right device architecture and has symbols to call and you know what to do with the data returned.
Another Hint: there is a way to handle C pointers in swift see docu which become swift datatypes which you can use to go the other way and declare functions to return those from swift.
And direct use of C in Swift is also possible. The compiler considers if you explicit mark some code as C. extern "C" { /* code */ } will cause the C++ compiler to remember, this is still C++ code to compile the function in such a way, it can be called from C (and Swift)
//Example.hpp //no target membership
#ifdef __cplusplus
#include <stdio.h>
class Example {
private:
const char * _name;
public:
Example(const char *name);
~Example(void);
int getLen(void);
};
#endif
There should be an Example.cpp and don't forget to tell Xcode you deal with c++ #ifdef __cplusplus + #endif
//Example.cpp //has target membership
#include "Example.hpp"
#ifdef __cplusplus
#include <stdio.h>
#include <string>
//code implementation according to example.hpp
Example::Example(const char *name) {
_name = name;
}
int Example::getLen() {
return (int)strlen(_name);
}
#endif
//ExampleWrapper.cpp //has target membership
#include "Example.hpp" //c++ header file
extern "C" int myCppFunction(const char *s)
{
// Create an instance of Example, defined in the library
// and call getLen() on it, return result.
return Example(s).getLen();
}
So this function needs to be declared in the bridging header to make use of it.
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
// for extern "C" functions declare them one by one here
// as implemented in ExampleWrapper.cpp
// becomes "func myCppFunction(_ s: UnsafePointer<Int8>!) -> Int32" in swift
int myCppFunction(const char * s);
and then call from swift..
os_log("The result from C++ is %u", myCppFunction("12345"))
So in fact, yes. Integrating a static lib A that calls static lib B in App is possible. Happy compiling as long you offer some header for each part that needs to know what is inside the head of the other lib. That is true for Apps as it is true for libs and frameworks under each other.
Edit here some important stuff to read about Swift Package Manager C support https://github.com/apple/swift-evolution/blob/master/proposals/0038-swiftpm-c-language-targets.md
As long as the libraries export Objective-C compatible symbols, it doesn't matter if they're written in Objective-C, or Swift, or C++, or any other compiled language.
And we know that the Swift compiler exports Objective-C compatible symbols for all declarations that are marked with #objc (either explicitly or implicitly).
From a consumer perspective it doesn't matter which language generated the libraries, as long as the Objective-C compiler/linker can consume the symbols exported by those libraries.

How to compile .h file which has struct definition with default values [duplicate]

This question already has an answer here:
Force Header Files to Compile as C++ in Xcode
(1 answer)
Closed 2 years ago.
I'm trying to use a 3rd party sample code as part of my Objective-C application.
However, when trying to compile my project I get a lot of compiler errors.
The objc syntax that is used in the sample is quite strange and I believe that it is compiled as something else within the project.
For example, as part of the header file the struct definition has default values:
File.h
struct Options
{
int count = 100;
}
...
In their project, the above header file would compile just fine, but when I try to compile it I see an Xcode error:
Expected ';' at end of declaration list
I'm not an objective-c expert, but from what I've read and also found as part of other posts data types cannot have default values, but somehow it compiles fine in the Xcode sample app.
Please let me know if you need more info or other examples of what would compile fine in their project and doesn't work when I copy and paste the code into mine.
Edit:
Force Header Files to Compile as C++ in Xcode
Individually header files doesn't compiled. Compiled source files where they included. If you include them in .c they will be compiled like C, if in .m - like Objective-c, if in .cpp - like C++, if in .mm - like Objective-C++.
My issue was that I was using this header file into a .m file which compiles it to an Objective-C standard. When I change the extension to .mm everything worked fine.
When you think of objective-C as actually being C its more clear why defaults are not set in .h files
This does not apply to the rules of default sizes which are needed when no flexible memory allocation for a data type is available by default, like for (as is) most data types in C.
Even this two sentences already show the difficulty to distinguish what is meant with "default".
Which is why you end up with definition of initiation processes and functions to declare what exactly is "default" in the other file.
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
int count;
} Options;
typedef struct {
int foo;
Options bar[100];
} Foo;
struct Bar {
Foo lotsof;
}
void MyInitiationFunction(Bar *b);
// definition of MyInitiationFunction in .m/.c file
#ifdef __cplusplus
}
#endif
but there is the concept of enum that can trick your mind where defined enumeration default states are what you build some stuff on, which is not a value.

Make a objective C method that uses a swift protocol as parameter public accesable

I have an objective-c method that uses a swift protocol as a parameter type. The signature looks like + (void) my_ObjC_method: (id<my_Swift_protocol>) parameter_name;
I generally know how to make swift protocols accessible to objective C.
I implemented it this way:
#objC protocol my_Swift_protocol : class {
//...methods go here
}
My problem is that I want to make my_ObjC_method public accessible. That would normally be done by simply adding it to the header file in the #interface part. Sadly, this requires to import the bridging header to the .h file, so that the .h file knows my swift protocol and recognizes it as a valid type. But you can't import the automatically generated bridging header into other header files.
What would be a good approach to solve or work around this problem?
Maybe you can use #protocol directive as a forward declaration.
MyClass.h:
#import <Foundation/Foundation.h>
#protocol my_Swift_protocol;
#interface MyClass : NSObject
+ (void) my_ObjC_method: (id<my_Swift_protocol>) parameter_name;
#end

How to access an internal Swift class in Objective-C within the same framework?

Working on a mixed framework. imported inside the Obj-C file but the internal classes are not visible, only the public ones.
The documentation clearly states the internal clasees should be available between Swift and Obj-C:
Importing Swift into Objective-C To import a set of Swift files in the same framework target as your Objective-C code, you don’t
need to import anything into the umbrella header for the framework.
Instead, import the Xcode-generated header file for your Swift code
into any Objective-C .m file you want to use your Swift code from.
Because the generated header for a framework target is part of the
framework’s public interface, only declarations marked with the public
modifier appear in the generated header for a framework target. You
can still use Swift methods and properties that are marked with the
internal modifier from within the Objective-C part of your framework,
as long they are declared within a class that inherits from an
Objective-C class. For more information on access-level modifiers, see
Access Control in The Swift Programming Language (Swift 2).
Code Sample (Create a new project with a framework)
// SwiftObject.swift
public class SwiftObject: NSObject {
public class func doSomething() {}
}
internal class YetAnotherSwiftObject: NSObject {
internal class func doSomething() {}
}
// SomeObject.m file
#implementation SomeObject
- (void)someMethod {
[SwiftObject doSomething];
}
- (void)someOtherMethod {
[YetAnotherSwiftObject doSomething]; // Use of undeclared identifier
}
#end
As indicated in the docs, declarations marked with internal modifier don't appear in the generated header, so the compiler does not know about them and thus complaints. Of course, you could send messages using performSelector approach, but that's not convenient and bug-prone. We just need to help the compiler know that those declarations are there.
First, we need to use #objc attribute variant that allows you to specify name for your symbol in Objective-C:
// SwiftObject.swift
#objc(SWIFTYetAnotherSwiftObject)
internal class YetAnotherSwiftObject: NSObject {
internal class func doSomething() {}
}
And then you just need to create #interface declaration with the methods you want to use in your code - so the compiler will be happy, and also apply SWIFT_CLASS macro with the symbol name you've specified earlier - so the linker would pick the actual implementation:
// SomeObject.m file
SWIFT_CLASS("SWIFTYetAnotherSwiftObject")
#interface YetAnotherSwiftObject : NSObject
+ (void)doSomething;
#end
#implementation SomeObject
- (void)someOtherMethod {
[YetAnotherSwiftObject doSomething]; // Should work now !!!
}
#end
I've used the interface declaration in .m file just for clarity, the better option would be to combine such declarations in .h file, and include it.
By declaring methods in that interface we're making a promise to compiler, and it won't complain if you'll put there a method that does not exist (or with wrong signature, etc.) Obviously, you'll crash in runtime in that case - so be cautious.
For me it just worked by checking: "Allow app extension API only". You find it by going to the project setting, select your target and then it is in the General tab under Deployment Info.
Can someone explain to me, why this does solve the problem?
While the above solution works (https://stackoverflow.com/a/33159964/5945317), it seems overly complicated and unintuitive:
Complicated, because it seems to add more things than necessary – I will provide a smoother solution below.
Unintuitive, because the objc macro SWIFT_CLASS resolves to SWIFT_RUNTIME_NAME, and the provided value is not actually the runtime name – nor is the objc class name in the header matching the Swift attribute param in #objc. Still, surprisingly, the solution works – but to me it is not clear why.
Here is what we have tested in our own project, and believe to be the better solution (using the example above):
// YetAnotherSwiftObject.swift
#objc(OBJCPREFIXYetAnotherSwiftObject)
internal class YetAnotherSwiftObject: NSObject {
#objc internal class func doSomething() {}
}
// OBJCPREFIXYetAnotherSwiftObject.h
#interface OBJCPREFIXYetAnotherSwiftObject : NSObject
+ (void)doSomething;
#end
That's it. The interface looks like a regular objc interface. This gives the added benefit that you can include it in other header files (which you cannot do if you use the SWIFT_CLASS macro, as it comes from the autogenerated Swift header file, which in turn you cannot include in an objc header, due to circular dependency).
On the Swift side, the only thing relevant is that you provide the class with the proper objc name. Mind that I only used the name prefix for language consistency – you can even just use YetAnotherSwiftObject everywhere (i.e., in the objc header and in the #objc attribute in Swift – but you need to keep this attribute with explicit naming in any case, and need to keep it consistent with the class name in the header).
This also makes your life easier if you're in the process of converting your objc framework step by step to Swift. You just keep the objc header as before, and now provide the implementation in Swift.
Methods and properties that are marked with the internal modifier and declared within a class that inherits from an Objective-C class are accessible to the Objective-C runtime.
so let's make use of that:
class MyInternalClass: NSObject {
#objc var internalProperty = 42
}
#interface MyPublicClass()
#end
#implementation MyPublicClass
+ (void) printValue {
Class myInternalClass = NSClassFromString(#"MyPackageNameIfAny.MyInternalClass");
id myInternalClassInstance = [myInternalClass new];
int value = [myInternalClassInstance performSelector:#selector(internalProperty)];
NSLog(#"Value is %d ", value); // "value is 42"
}
#end
Using the SWIFT_CLASS macro and #objc class attribute could easily lead to errors when archiving. This approach is safer.

Can't use Swift classes inside Objective-C

I try to integrate Swift code in my app.My app is written in Objective-C and I added a Swift class. I've done everything described here. But my problem is that Xcode haven't created the -Swift.h file, only the bridging headers. So I created it, but it's actually empty.
I can use all my ObjC classes in Swift, but I can't do it vice versa. I marked my swift class with #objc but it didn't help. What can I do now?
EDIT: Apple says:" When you import Swift code into Objective-C, you rely on an Xcode-generated header file to expose those files to Objective-C. [...] The name of this header is your product module name followed by adding “-Swift.h”. "
Now when I want to import that File, it gives an error:
//MainMenu.m
#import "myProjectModule-Swift.h" //Error: 'myProjectModule-Swift.h' file not found
#implementation MainMenu
Here is my FBManager.swift file:
#objc class FBManager: NSObject {
var descr = "FBManager class"
init() {
super.init()
}
func desc(){
println(descr)
}
func getSharedGameState() -> GameState{
return GameState.sharedGameState() //OK! GameState is written in Objective-C and no error here
}
}
I spent about 4 hours trying to enable Swift in my Xcode Objective-C based project. My myproject-Swift.h file was created successfully, but my Xcode didn't see my Swift-classes. So, I decided to create a new Xcode Objc-based project and finally, I found the right answer! Hope this post will help someone :-)
Step by step Swift integration for Xcode Objc-based project:
Create new *.swift file (in Xcode) or add it by using Finder.
Create an Objective-C bridging header when Xcode asks you about that.
Implement your Swift class:
import Foundation
// use #objc or #objcMembers annotation if necessary
class Foo {
//..
}
Open Build Settings and check these parameters:
Defines Module : YES
Copy & Paste parameter name in a search bar
Product Module Name : myproject
Make sure that your Product Module Name doesn't contain any special characters
Install Objective-C Compatibility Header : YES
Once you've added *.swift file to the project this property will appear in Build Settings
Objective-C Generated Interface Header : myproject-Swift.h
This header is auto-generated by Xcode
Objective-C Bridging Header : $(SRCROOT)/myproject-Bridging-Header.h
Import Swift interface header in your *.m file.
#import "myproject-Swift.h"
Don't pay attention to errors and warnings.
Clean and rebuild your Xcode project.
Profit!
Don't create the header file yourself. Delete the one you created.
Make sure your Swift classes are tagged with #objc or inherit from a class that derives (directly or indirectly) from NSObject.
Xcode won't generate the file if you have any compiler errors in your project - make sure your project builds cleanly.
Allow Xcode to do its work, do not add/create Swift header manually. Just add #objc before your Swift class ex.
#objc class YourSwiftClassName: UIViewController
In your project setting search for below flags and change it to YES (Both Project and Target)
Defines Module : YES
Always Embed Swift Standard Libraries : YES
Install Objective-C Compatibility Header : YES
Then clean the project and build once, after build succeed (it should probably) import below header file in your objective-c class .m file
#import "YourProjectName-Swift.h"
Boooom!
Also probably helpful for those of you with a Framework target:
The import statement of the auto-generated header file looks a bit different from app targets. In addition to the other things mentioned in other answers use
#import <ProductName/ProductModuleName-Swift.h>
instead of
#import "ProductModuleName-Swift.h"
as per Apples documentation on Mix & Match for framework targets.
Details: Objective-C project with Swift 3 code in Xcode 8.1
Tasks:
Use swift enum in objective-c class
Use objective-c enum in swift class
FULL SAMPLE
1. Objective-C class which use Swift enum
ObjcClass.h
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, ObjcEnum) {
ObjcEnumValue1,
ObjcEnumValue2,
ObjcEnumValue3
};
#interface ObjcClass : NSObject
+ (void) PrintEnumValues;
#end
ObjcClass.m
#import "ObjcClass.h"
#import "SwiftCode.h"
#implementation ObjcClass
+ (void) PrintEnumValues {
[self PrintEnumValue:SwiftEnumValue1];
[self PrintEnumValue:SwiftEnumValue2];
[self PrintEnumValue:SwiftEnumValue3];
}
+ (void) PrintEnumValue:(SwiftEnum) value {
switch (value) {
case SwiftEnumValue1:
NSLog(#"-- SwiftEnum: SwiftEnumValue1");
break;
case SwiftEnumValue2:
case SwiftEnumValue3:
NSLog(#"-- SwiftEnum: long value = %ld", (long)value);
break;
}
}
#end
Detect Swift code in Objective-C code
In my sample I use SwiftCode.h to detect Swift code in Objective-C. This file generate automatically (I did not create a physical copy of this header file in a project), and you can only set name of this file:
If the compiler can not find your header file Swift code, try to compile the project.
2. Swift class which use Objective-C enum
import Foundation
#objc
enum SwiftEnum: Int {
case Value1, Value2, Value3
}
#objc
class SwiftClass: NSObject {
class func PrintEnumValues() {
PrintEnumValue(.Value1)
PrintEnumValue(.Value2)
PrintEnumValue(.Value3)
}
class func PrintEnumValue(value: ObjcEnum) {
switch value {
case .Value1, .Value2:
NSLog("-- ObjcEnum: int value = \(value.rawValue)")
case .Value3:
NSLog("-- ObjcEnum: Value3")
break
}
}
}
Detect Objective-C code in Swift code
You need to create bridging header file. When you add Swift file in Objective-C project, or Objective-C file in swift project Xcode will suggest you to create bridging header.
You can change bridging header file name here:
Bridging-Header.h
#import "ObjcClass.h"
Usage
#import "SwiftCode.h"
...
[ObjcClass PrintEnumValues];
[SwiftClass PrintEnumValues];
[SwiftClass PrintEnumValue:ObjcEnumValue3];
Result
MORE SAMPLES
Full integration steps Objective-c and Swift described above. Now I will write some other code examples.
3. Call Swift class from Objective-c code
Swift class
import Foundation
#objc
class SwiftClass:NSObject {
private var _stringValue: String
var stringValue: String {
get {
print("SwiftClass get stringValue")
return _stringValue
}
set {
print("SwiftClass set stringValue = \(newValue)")
_stringValue = newValue
}
}
init (stringValue: String) {
print("SwiftClass init(String)")
_stringValue = stringValue
}
func printValue() {
print("SwiftClass printValue()")
print("stringValue = \(_stringValue)")
}
}
Objective-C code (calling code)
SwiftClass *obj = [[SwiftClass alloc] initWithStringValue: #"Hello World!"];
[obj printValue];
NSString * str = obj.stringValue;
obj.stringValue = #"HeLLo wOrLd!!!";
Result
4. Call Objective-c class from Swift code
Objective-C class (ObjcClass.h)
#import <Foundation/Foundation.h>
#interface ObjcClass : NSObject
#property NSString* stringValue;
- (instancetype) initWithStringValue:(NSString*)stringValue;
- (void) printValue;
#end
ObjcClass.m
#import "ObjcClass.h"
#interface ObjcClass()
#property NSString* strValue;
#end
#implementation ObjcClass
- (instancetype) initWithStringValue:(NSString*)stringValue {
NSLog(#"ObjcClass initWithStringValue");
_strValue = stringValue;
return self;
}
- (void) printValue {
NSLog(#"ObjcClass printValue");
NSLog(#"stringValue = %#", _strValue);
}
- (NSString*) stringValue {
NSLog(#"ObjcClass get stringValue");
return _strValue;
}
- (void) setStringValue:(NSString*)newValue {
NSLog(#"ObjcClass set stringValue = %#", newValue);
_strValue = newValue;
}
#end
Swift code (calling code)
if let obj = ObjcClass(stringValue: "Hello World!") {
obj.printValue()
let str = obj.stringValue;
obj.stringValue = "HeLLo wOrLd!!!";
}
Result
5. Use Swift extension in Objective-c code
Swift extension
extension UIView {
static func swiftExtensionFunc() {
NSLog("UIView swiftExtensionFunc")
}
}
Objective-C code (calling code)
[UIView swiftExtensionFunc];
6. Use Objective-c extension in swift code
Objective-C extension (UIViewExtension.h)
#import <UIKit/UIKit.h>
#interface UIView (ObjcAdditions)
+ (void)objcExtensionFunc;
#end
UIViewExtension.m
#implementation UIView (ObjcAdditions)
+ (void)objcExtensionFunc {
NSLog(#"UIView objcExtensionFunc");
}
#end
Swift code (calling code)
UIView.objcExtensionFunc()
Make sure your project defines a module and you have given a name to the module. Then rebuild, and Xcode will create the -Swift.h header file and you will be able to import.
You can set module definition and module name in your project settings.
I had the same issue and it turned out special symbols in the module name are replaced by xcode (in my case dashes ended up being underscores). In project settings check "module name" to find the module name for your project. After that either use ModuleName-Swift.h or rename the module in settings.
The file is created automatically (talking about Xcode 6.3.2 here). But you won't see it, since it's in your Derived Data folder. After marking your swift class with #objc, compile, then search for Swift.h in your Derived Data folder. You should find the Swift header there.
I had the problem, that Xcode renamed my my-Project-Swift.h to my_Project-Swift.h Xcode doesn't like
"." "-" etc. symbols. With the method above you can find the filename and import it to a Objective-C class.
For Swift 5:
Add the #objc keyword to your class and methods
Add public keyword to your class and methods
Let your class inherit from NSObject
Build Project
Put #import "MyProject-Swift.h" in your Objective-C file
#objc
public class MyClass: NSObject {
#objc
public func myMethod() {
}
}
Just include
#import "myProject-Swift.h" in .m or .h file
P.S You will not find "myProject-Swift.h" in file inspector it's hidden. But it is generated by app automatically.
#sig answer is one of the best, however, it did not work for me with the old project (not new!), I needed some modifications. After a lot of variations I found the recipe for me (using XCode 7.2):
Product Module Name : $(PRODUCT_NAME:c99extidentifier)
Defines Module : NO
Embedded Content Contains Swift : NO
Install Objective-C Compatibility Header : YES
Objective-C Bridging Header : ProjectName-Bridging-Header.h
The last point (5) was crucial. I put it only on the second section (Targets field), the Project field should be left empty: Otherwise, it did not generate the right "Project-Swift.h" file for me (it did not include swift methods).
There is two condition,
Use your swift file in objective c file.
Use your objective c file in swift file.
So, For that purpose, you have to follow this steps:
Add your swift file in an objective-c project or vice-versa.
Create header(.h) file.
Go to Build Settings and perform below steps with search,
search for this text "brid" and set a path of your header file.
"Defines Module": YES.
"Always Embed Swift Standard Libraries" : YES.
"Install Objective-C Compatibility Header" : YES.
After that, clean and rebuild your project.
Use your swift file in objective c file.
In that case,First write "#objc" before your class in swift file.
After that ,In your objective c file, write this,
#import "YourProjectName-Swift.h"
Use your objective c file in swift file.
In that case, In your header file, write this,
#import "YourObjective-c_FileName.h"
I hope this will help you.
In my case, apart from these steps:
Product Module Name : myproject
Defines Module : YES
Embedded Content Contains Swift : YES
Install Objective-C Compatibility Header : YES
Objective-C Bridging Header : $(SRCROOT)/Sources/SwiftBridging.h
I have needed to put the class as public in order to create productName-Swift.h file:
import UIKit
#objc public class TestSwift: NSObject {
func sayHello() {
print("Hi there!")
}
}
I just discovered that adding a directory of swift files to a project won't work. You need to create a group first for the directory, then add the swift files...
I had the same problem and finally it appeared that they weren't attached to the same targets.
The ObjC class is attached to Target1 and Target2, the Swift class is only attached to the Target1 and is not visible inside the ObjC class.
Hope this helps someone.
my problem was I got stuck after xcode created the bridge file but still I got error in header file name MYPROJECTNAME-swift.h
1.I check in terminal and search for all auto created swift bridge files:
find ~/library/Developer/Xcode/DerivedData/ -name "*-Swift.h"|xargs basename|sort -
you see what xcode created.
in my case, I had space in my project name and xcode replace this is '_'
When you add new Swift files to the project, please, make sure that you add them to correct targets.
Please, make sure that every swift file you're going to use inherits NSObject class and annotated with #ObjCMembers
Change to YES inside the build settings under the option ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES.
Change to YES inside the build settings under the option DEFINES_MODULE.
Using Swift Classes in Objective-C
If you are going to import code within an App Target (Mixing Objective-C and Swift in one project) you should use the next import line #import "<#YourProjectName#>-Swift.h" to expose Swift code to Objective-C code [Mixing Swift and Objective-C code in a project]
In this post I will describe how to import Swift static library to Objective-C code
Objective-C consumer -> Swift static library
Xcode version 10.2.1
Create Swift static library
Follow Create Swift static library with next additions:
Expose Swift API. To use Swift's functions from Objective-C[About]
After building you should find a <product_name>-Swift.h file that should be located into DerivedSources [File not found]
Objective-C consumer with Swift static library
Drag and drop the binary into the Xcode project[About]
Link Library[Undefined symbols] [Link vs Embed]
Project editor -> select a target -> General -> Linked Frameworks and Libraries -> add -> Add Others... -> point to `lib<product_name>.a` file
//or
Project editor -> select a target -> Build Phases -> Link Binary With Libraries -> add -> Add Others... -> point to `lib<product_name>.a` file
Add Library Search paths[Library not found for] [Recursive path]
Project editor -> select a target -> Build Settings -> Search Paths -> Library Search paths -> add path to the parent of `lib<product_name>.a` file
Add Header Search Paths[Module not found] [Recursive path]
Project editor -> select a target -> Build Settings -> Search Paths -> Header Search Paths -> add path to generated `<product_name>-Swift.h` file
Add empty .swift file to the Objective-C project.[Undefined symbols] When Xcode ask press Create Bridging Header(it will create module_name-Bridging-Header.h) and setup a path to this file in
Project editor -> select a target -> Build Settings -> Swift Compiler - General -> Objective-C Bridging Header
Import module to the Objective-C client code[File not found] [module_name]
#import "module_name-Swift.h"
More examples here
I have the same error: myProjectModule-Swift.h file not found", but, in my case, real reason was in wrong deployment target:
"Swift is unavailable on OS X earlier than 10.9; please set MACOSX_DEPLOYMENT_TARGET to 10.9 or later (currently it is '10.7')"
so, when I've changed deployment target to 10.9 - project had been compiled successfully.
My issue was that the auto-generation of the -swift.h file was not able to understand a subclass of CustomDebugStringConvertible. I changed class to be a subclass of NSObject instead. After that, the -swift.h file now included the class properly.
I had issues in that I would add classes to my objective-c bridging header, and in those objective-c headers that were imported, they were trying to import the swift header. It didn't like that.
So in all my objective-c classes that use swift, but are also bridged, the key was to make sure that you use forward class declarations in the headers, then import the "*-Swift.h" file in the .m file.
I didnt have to change any settings in the build or add #obj to the class.
All I had to do was to create bridge-header which was automatically created when I created Swift classes into Objective-c project. And then I just had to do
import "Bedtime-Swift.h" <- inside objective-c file that needed to use that swift file.
well, after reading all the comments and trying and reading and trying again, I managed to include swift classes into my Big obj-c project.
So, thanks for all the help.
I wanted to share one tip that helped me understand the process better.
In the .m class, went to the import line of the swift target name #import "myTargetName-Swift.h"
and clicked the key:
command + mouse click -> Jump to definition
There you can see all the translation from swift to obj-c and ther you will find the various functions re-declared in obj-c.
Hope this tip will help you as much as it helped me.
XCode 11.3.1:
When I want to use an Swift inner class in a objc code, it does not compile for ther error "undefined symbol"(for bother inner class and outer class), I checked the generated "-swift.h" header and both classes are there.
After trying for hours I convert the inner class to a normal class and it compiles.
I clean the project, delete the DerivedData folder and it compiles.
I use CocoaPods and the Swift class from my library couldn't be located from the Objective-C code in the example app because it's project and target were named the same as the library, so I had to remove the Objective-C Generated Interface Name values so they didn't conflict with the ones from the library.
Archiving will be successful already tested
How to call a swift function (that could be in a swift framework also) in objective c project or react native project
it will work for react-native also
follow these steps :
Open Build Settings and check these parameters:
Defines Module : YES
in AppDelegate.h
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
#class KB;
#interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
#property (strong, nonatomic) KB *appkb;
#end
in AppDelegate.m
#import "AppDelegate.h"
#import "ProductModuleName-Swift.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.appkb methodReceiveSwiftClass];
[self.appkb methodEvents:event prop:properties];
}
#end
KB.swift
import Foundation
// import framework if using a swift framework in objective c or react native native modules.
#objc public class KB:NSObject{
#objc public func methodReceiveSwiftClass(){
//write anything here....
}
#objc public func methodEvents(_ event: String, prop: String){
//write anything here
//func with params
}
}
ProjectModuleName-Bridging-Header.h
#import "React/RCTBridgeModule.h"
#import "AppDelegate.h"
After doing everything above, I still got errors. My problem ended up being that the Swift files I needed weren't added to the bundle resources for some reason.
I fixed this by going to [MyTarget] > Build Phases > Copy Bundle Resources, then clicked the plus button and added the Swift files.

Resources