If you don't want to make your Objective-C headers public to use in Swift, you have to create a module.map
file at the root of your project and add all your internal/private headers:
module FrameWorkProjectName_Internal {
// import your private headers here
export *
}
Then, in your SWIFT_INCLUDE_PATHS
build settings add $(SRCROOT)/FrameWorkProjectName
so that this module can be found by Swift classes.
To use the Objective-C code of the said module you have to import FrameWorkProjectName_Internal
in your Swift file.
To use internal Swift classes in your Objective-C code, first you mark the classes/methods with @objc
/@objcMembers
. Since you don't want to make your Swift interface public you can either use performSelector
to send messages OR you can manually create a header containing all your Swift interface definitions. For example, define type symbol name or selector name in your swift file with @objc
attribute:
@objc(FrameWorkProjectName_SwiftType)
class SwiftType: NSObject {
func call() { /* Do something */ }
}
and then define the swift type interface in your header file:
SWIFT_CLASS("FrameWorkProjectName_SwiftType")
@interface SwiftType : NSObject
- (void)call;
@end
When defining type symbol names make sure that it doesn't conflict with other names in your or any other external module. To avoid this try to include your framework name in symbol name.
Be advised, that SWIFT_CLASS
macro is generated as part of {TargetName}-Swift.h
header.
Some Clarifications:
These are some clarification points answering some comments:
- The header {FrameWorkProjectName}.h is not a bridging header, it's the umbrella header of a framework, where only public headers can be exposed, which contradicts the requirements of the question.
Yes for the framework it is called umbrella header, but you can achieve the same effect of bridging header in app targets, the only difference being the headers have to be public to be included here. And the side effect being the declarations in these headers would be exposed to consumers of your library.
While this point doesn't address your question specifically, I put it as a workaround if you think the actual action is quite cumbersome and requires a lot of manual work for your time constraints.
For framework projects, a bridging header is just not supported, so you have to rely on swift-generated headers which only include public interfaces
Swift generated header is used to expose your Swift interfaces to Objective-C. They basically achieve the opposite of what bridging headers do. So in short,
Bridging header => Expose Objective-C declarations to Swift in app target.
Umbrella header => Expose Objective-C declarations to Swift in framework target and targets consuming the framework.
Swift generated header => Expose Swift interfaces to Objective-C (for frameworks declarations has to be public)
For more detail, you can go through official docs for importing objective-c into swift and importing swift into objective-c.
- A few times you suggest to make Swift/Objective-C interface public, which is not really a solution to the question, as it looks for a way to avoid that.
These also I put as workarounds if you think the actual action is quite cumbersome and requires a lot of manual work for your time constraints.
- You cannot use SWIFT_CLASS macro without importing the -Swift.h generated header. It's redundant when it comes to use of internal classes
You are correct, unfortunately, I missed that. Thanks for adding this point.