#import ProjectName-Swift.h into header file Can't use swift as .h property? - ios

So I'm trying to use an #objc swift class as a property on my objective-c header file.
example
#objc class SwiftClass: NSObject {
}
#interface ObjcObject : NSObject
#pragma mark - Public Properties -
#property (nonatomic, weak) SwiftClass* swiftClass;
However if I #import ProjectName-Swift.h it gives me the error that "'ProjectName-Swift.h'file not found'
I found an answer here that implies you can't actually import Swift into a header file https://stackoverflow.com/a/29951314/3877767
How then am I supposed to use swift code together with objc code? I would not call swift and objc interoperable if you can't use #objc marked swift classes as properties on and objc header file
So inside of my App-Bridging-Header.h
#import "ObjcClass.h"
and inside of my ObjcClass.h
#import "ProjectName-Swift.h"
This gives the error ProjectName-Swift.h can't find file
Either removing the #import ProjectName-Swift.h, or the #import ObjcClass.hfixes the problem, but then I can't use the Swift/OBJC code respectively

You don't import the header file. You give it to the compiler as a so-called "bridging header" that tells the compiler what to share between the two language environments.
You need to put your header file under the Objective-C Bridging Header as shown below:

Related

Swift framework - Use Swift class reference in Objective-C class

I am creating Swift framework in which I have to use Objective-C class. So I went through this link. This is the public header of my framework :
#import <UIKit/UIKit.h>
//! Project version number for Test.
FOUNDATION_EXPORT double TestVersionNumber;
//! Project version string for Test.
FOUNDATION_EXPORT const unsigned char TestVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Test/PublicHeader.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <MyTest/MPAppDelegateProxy.h>
Now in class MPAppDelegateProxy, I have to use a Swift class which I have created. This is :
#import "MPAppDelegateProxy.h"
#import "MyTest.h"
#implementation MPAppDelegateProxy
+ (void)proxyAppDelegate {
[MPGlobal MPLog:#"App delegate not set, unable to perform automatic setup." file:#"MPAppDelegateProxy.m" function:#"proxyAppDelegate" line:32];
// rest of code
}
MPGlobal is one of my Swift class. But I am getting :
Use of undeclared identifier 'MPGlobal'
Note : I have added #objC before MPGlobal.
You need to import <Target>-Swift.h file.
This is known as Objective-C Generated Interface Header Name.
You can find it in your Target's build settings.
This file is auto generated by compiler and it needs to be imported in Objective-C files.
change the SWIFT_OBJC_INTERFACE_HEADER_NAME build setting and making it the same across different targets. To do so change the instruction that generates this property from $(SWIFT_MODULE_NAME)-Swift.h to $(PROJECT_NAME)-Swift.h as explained here
After doing this Clean Build Folder by pressing Alt and going into Product menu. Since name of header is shared among targets now it can be imported once in the .m ObjectiveC file and all targets can benefit from Swift classes.
If after building it still shows the error, ensure that the header can be reached from XCode by Cmd clicking on its name. It should open a file that contains code similar to this:
SWIFT_CLASS("_TtC27ProjectName_Summary11MyClass")
#interface MyClass : NSObject
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
If need to ensure that those headers are being generated open a terminal and use this command
find ~/Library/Developer/Xcode/DerivedData -name "*Swift.h"
You should see one header for each target
Another issue that happened to me after those changes is that it started giving errors on ObjectiveC code that I didn't touch. The problem was due to the position of the import, as reported here:
Exactly where at the top of a .m file you #import the hidden bridging
header can make a difference. The usual sign of trouble is that you
get an “Unknown type name” compile error, where the unknown type is a
class declared in Objective-C. The solution is to #import the .h file
containing the declaration for the unknown type in your Objective-C
files as well, before you #import the hidden bridging header. Having
to do this can be an annoyance, especially if the Objective-C file in
question has no need to know about this class, but it resolves the
issue and allows compilation to proceed.
At the very end the code compiles and runs on device and simulator!
Original answer
Also you can try this,
You needed to import the -Swift.h for for both the framework and the app target
For Example :
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#import "XLPagerTabStrip-Swift.h"
#import "RealmSwift-Swift.h"
...... // Add all frameworks, subclasses, and dependance ios frameworks
#import "MyProject-Swift.h"
You can read this article How to import file header and check paths

Objective C bridging header file not found

I have a class name AppState which is using a swift class object
#import "Sonic-Swift.h"
#interface AppState : NSObject
#property (class) NSMutableArray<"Swift class" *> *entity;
Now I need to use this class (AppState) in the swift file. So I'm trying to import this class in the bridging header.
But after importing this file the app gives an error on the "#import "Sonic-Swift.h"" line "File not found".
failed to emit precompiled header '/Users/krishna_mac_2/Library/Developer/Xcode/DerivedData/Apps-gqelclyzwvyomhcchmjjsejrznaw/Build/Intermediates.noindex/PrecompiledHeaders/Sonic-Bridging-Header-swift_3RJ3MQEOEFTPD-clang_26Q2UBYWMY12Y.pch' for bridging header '/Users/krishna_mac_2/Documents/Documents/Documents/Documents/Documents/Github/Sonic/iOS/Sonic/Sonic-Bridging-Header.h'
import "Sonic-Swift.h"
should be in .m file only.
If you want to use Swift class in .h file then you should use
#class MySwiftClass;

Cannot call Swift method in Objective-C .m file

I have big problem with one part of my code.
I have simple function in my ViewController.swift file (on end):
ViewController.swift
#objc class Constant: NSObject {
override init() {}
#objc class func parseApplicationId() -> String { return "lol" }
#objc func printSome() { print("teeeeest") }
}
Now I have one pod (charts graphic) what was written in Objective-C. So I created Bridging file called:
myprojectname-Swift.h
#import "EColumnChartViewController.h"
In header file of Objective-C file:
HEADER.h
#import <UIKit/UIKit.h>
#import "EColumnChart.h"
#import "myprojectname-Swift.h"
#class Constant;
#interface Constant : NSObject
-(void)printSome;
#end
and in my FILE.m I have this:
#import "myprojectname-Swift.h"
- (void)viewDidLoad
{
[super viewDidLoad];
Constant * sis = [[Constant alloc] init];
[sis printSome];
}
My problem is:
When I build a project, Xcode call me error:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_Constant", referenced from:
objc-class-ref in EColumnChartViewController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
What I trying to make solution:
New Bridging file
Switching off some parts of Build Settings
#implementation Constant -> Thread 1 error
I just want to call Swift function into Objective-C file (easy call print console). Thanks for every idea.
Last words: I've checked so many posts on Stackoverflow.
Duplicate classes
The main issue appears to be that you have created two classes named Constant: one in Swift and another in Objective-C. You can only have one class with a given name.
This #objc class Constant: NSObject and #interface Constant : NSObject both create the same class. Rename one of these.
Possibly incorrect bridging
The Swift bridging header is special. You can't just create a header file and expect that to work in Swift.
Ensure that the bridging header is properly set in Xcode.
Click the project at the top to open the config screen
Search for SWIFT_OBJC_BRIDGING_HEADER
Make sure the value points to your bridging header. For example: myprojectname/myprojectname-Bridging-Header.h
In the bridging header file, put the Objective-C import for the class that you want Swift to be able to use: #import "EColumnChartViewController.h"
Other Issues
In HEADER.h:
remove #class Constant;. This is doing nothing for you.
Move the #import for EColumnChart.h and myprojectname-Swift.h into the .m file only.
The FILE.m should have an #import HEADER.h. Every .m must import it's .h!
On the line #objc class Constant: NSObject, remove the #objc... it's obviously Objective-C because it extends NSObject.
As some commenters have stated, you have provided code with an astonishing number of problems. You should really take the time to learn Objective-C and/or Swift first. Start by watching some of the free WWDC videos or Googling for intro to iOS.
Make step by step above
You use #objcMembers above declare class in swift file.
Import <"Your_Project">-Swift.h in .m file.
objcMembers
class ObjectA: NSObject {
.....
}

Project-Swift.h file not found

I have a new Swift project with a few files, I've needed to add some Objc code.
In Build Settings, my Objective-C Generated Interface Header Name is MyProject-Swift.h
Product Module Name and Product Name are both MyProject.
My Objective-C Bridging Header is MyProject/MyProject-Bridging-Header.h
The contents of my Bridging Header are:
#ifndef MyProject_Bridging_Header_h
#define MyProject_Bridging_Header_h
#import "Blakey.h"
#endif
Blakey.h is pretty simple:
#import Foundation;
#import "MyProject-Swift.h"
#class KeyPair;
#interface Blakey: NSObject
- (void)createKeyPairForSeed:(NSString *)seed;
#end
And Blakey.m
#import <Foundation/Foundation.h>
#import "Blakey.h"
#implementation Blakey
- (void)createKeyPairForSeed:(NSString *)seed;
{
}
#end
(side note: I'm aware my function returns a void, that will be changed later once this issue is fixed so it returns an actual value)
Why is Xcode throwing an error at the #import "MyProject-Swift.h" in Blakey.h?
Project-Swift.h is a file auto generated by Xcode on successful compilation of the project. Catch here is the word successful compilation If your project has any compilation error Project-Swift.h file will not be generated. So in a way it becomes a deadlock. Bestway comment out all the lines that have compilation error and then manage to get it compile without any errors. Only after that Project-Swift.h will be generated.
Additional information, Once the Project-Swift.h file is generated if you open it and if you happened to see that your swift class is not imported there thats because Project-Swift.h imports only the classes that extends from NSObject So plain Swift classes will not be imported.
ISSUE:
You need to import Project-Swift.h in .m file and not .h file. So modify your Blakey as
#import <Foundation/Foundation.h>
#import "Blakey.h"
#import "MyProject-Swift.h"
#implementation Blakey
- (void)createKeyPairForSeed:(NSString *)seed;
{
}
Finally remove #import "MyProject-Swift.h" from Blakey.h
#import Foundation;
#class KeyPair;
#interface Blakey: NSObject
- (void)createKeyPairForSeed:(NSString *)seed;
#end
I had similar issue and almost ended up spending a whole day trying to figure out what wrong with my app.
So following the solution that's helped me :
Clear derived data
Create a class in swift with prefix of #objc for example #objc class mySwiftClass{...}
Build the project again
Et voila.. Should work now.
Why to add #objc?
this #objc prefix, tells the compiler to generate to your swift class a header file. it will add it to the "MyModule-Swift.h" file
I realize this is an old thread, but I had similar issues after adding a new target to a project. I solved it by adding a preprocessor macro (Build Settings -> Apple Clang - Preprocessing) only in said target and then importing the Swift.h file conditionally, like this:
#if DEV_VERSION
#import "Project_DEV-Swift.h"
#else
#import "Project-Swift.h"
#endif
My main target is called Project and the new target is Project DEV (the space is replaced with an underscore in the import), and the preprocessor macro is called DEV_VERSION.
After doing this, both targets build just fine.
<product_name>-Swift.h file not found
It is a kind of bridge(adapter) between Swift and Objective-C. This file contains Swift's API for Objective-C which was marked [#objc and #objcMembers].
You can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header file.
The header's name is generated from a <product_name>-Swift.h
[Mixing Objective-C and Swift ]
I had a similar issue whereby it would have this issue for anything other than live.
I resolved the issue by hardcoding "Product module name" & "Product name" to my project name. This avoids the need to have preprocessor logic in every file that includes swift code as demonstrated in Pauli Kettunen's solution.

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

Resources