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
}
}
This question is related to
ios
objective-c
swift
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 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.
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.
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.
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.
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.
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.
There is two condition,
So, For that purpose, you have to follow this steps:
Go to Build Settings and perform below steps with search,
After that, clean and rebuild your project.
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"
In that case, In your header file, write this,
#import "YourObjective-c_FileName.h"
I hope this will help you.
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.
Details: Objective-C project with Swift 3 code in Xcode 8.1
Tasks:
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
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.
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
}
}
}
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"
#import "SwiftCode.h"
...
[ObjcClass PrintEnumValues];
[SwiftClass PrintEnumValues];
[SwiftClass PrintEnumValue:ObjcEnumValue3];
Full integration steps Objective-c and Swift described above. Now I will write some other code examples.
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
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
Swift extension
extension UIView {
static func swiftExtensionFunc() {
NSLog("UIView swiftExtensionFunc")
}
}
Objective-C code (calling code)
[UIView swiftExtensionFunc];
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()
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.
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.
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
Xcode version 10.2.1
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]
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"
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 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.
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...
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.
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.
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.
@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):
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).
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 :-)
*.swift
file (in Xcode) or add it by using Finder.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:
YES
Copy & Paste parameter name in a search bar
myproject
Make sure that your Product Module Name doesn't contain any special characters
YES
Once you've added
*.swift
file to the project this property will appear in Build Settings
myproject-Swift.h
This header is auto-generated by Xcode
$(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.
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
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.
For Swift 5:
@objc
keyword to your class and methodspublic
keyword to your class and methodsNSObject
Put #import "MyProject-Swift.h"
in your Objective-C file
@objc
public class MyClass: NSObject {
@objc
public func myMethod() {
}
}
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!
In my case, apart from these steps:
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!")
}
}
Source: Stackoverflow.com