JDL
JDL

Reputation: 1507

Swift classes marked with @objc not being added to "-Swift.h" header in mixed Objective-C/Swift framework

I am attempting to convert an old statically linked library to a framework. With mixed swift and objective c in the static library, all headers are generated correctly. However, switching to a framework target and adding swift files, marked with the @objc header, the class is not added to the -Swift.h header. I can import the header, but swift classes are not found. This is in Xcode 10.2 and attempted using both Swift 4.2 and 5.

Are there any particular settings in XCode that will affect the generation of the *-Swift.h header in a mixed Objective C/Swift framework target?

Upvotes: 3

Views: 1132

Answers (2)

JDL
JDL

Reputation: 1507

The problem appears to be a combination of Apple's new build system, the expectations they set when compiling and the number of inter-dependencies in the project setup.

The new build system runs the Swift compilations in parallel. When having multiple library/framework dependencies that are mixed Objective C and Swift, the compiler appears to not generate the -Swift.h files on time. In static libraries, the -Swift.h files appear to be generated at the end of the Swift Compilation process, meaning they are not generated quickly enough to be used by the Objective C files when the Objective C compilation occurs. When generating a framework, it appears that the Compiler generates the header at the beginning of the compilation process and the Swift files are not fully compiled and the -Swift.h file does not generate appropriately with the Objective C class interfaces and protocols.

What this means ends up meaning is that we can not rely on the "target dependencies" to build the dependent projects correctly.

So how can we build our .framework of mixed Objective C and -Swift.h without a ton of manual scripting.

Here are the tricks I discovered that will work.

  1. Use the old build system. When using the new build system there is an error when it attempts to merge the module map for the static library file saying that it can not find the *-Swift.h file whether or not it exists.
  2. Create your framework by making it a wrapper around the static library by:
    • Giving them both the same product name and module name.
    • Add a single .Swift file to the framework build so that it has something to compile and will link the swift libraries.
    • link to the static library in the framework.
    • Add all necessary headers to the public headers of the framework.
    • Add all public headers to the umbrella header.
    • Use a Run script phase to copy the *-Swift.h file from the static library build to the framework product post compile.
    • For any public headers that include the *-Swift.h, you may need to post process the header and replace the *-Swift.h import with the appropriate framework import ie . This would not be recommended due to possible cyclical imports in the umbrella header.
  3. When running a clean, build the framework target first manually, before building the application target.

Below is an example script for copying the *-Swift.h file post build.

header_file="${TARGET_TEMP_DIR}/../${PRODUCT_MODULE_NAME}.build/DerivedSources/${PRODUCT_MODULE_NAME}-Swift.h"
header_dir="${BUILT_PRODUCTS_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}"
mkdir -p "$DIR"
echo "copying $header_file $header_dir"
cp -f "$FILE" "$DIR"

UPDATED

Marking all modules Swift compilation mode to "Whole Module" appears to have a positive affect on this issue, but I have not fully tested it.

Upvotes: 2

Mateusz
Mateusz

Reputation: 1224

I had a similar issue. In my case it was a known issue in Xcode 10.2:

https://developer.apple.com/documentation/xcode_release_notes/xcode_10_2_release_notes

If you’re building a framework containing Swift code and using lipo to create a binary that supports both device and simulator platforms, you must also combine the generated Framework-Swift.h headers for each platform to create a header that supports both device and simulator platforms. (48635615) ...

In my case all I had to do was to update the Carthage to the newest version 0.33.0

Upvotes: 2

Related Questions