Xcode framework: Swift Generated Interface not in DerivedSources folder - ios

Xcode 10, iOS 12
I have a project, that has 2 targets: an app and a framework. I use both Swift and Objective-C. I'm trying to reference Swift classes from Objective-C. I've set the SWIFT_OBJC_INTERFACE_HEADER_NAME property to "SwiftInterface.h" in the project, and when the target is "app", all is working well, I can include and use Swift classes. With the same settings, the "framework" doesn't compile, because it can't find the generated header.
What I have investigated:
The "app" generates the header file to {TempFolder}/{Project}.build/Debug-iphoneos/MyApp.build/DerivedSources/SwiftInterface.h
The "framework" has the corresponding folder, but the header file is missing.
I've read, that this might be because of Swift compiler errors, but it is not, since the file is actually generated in the MyFramework.framework/Headers folder, where the public headers are.
Now, if I copy this header file to the DerivedSources folder manually, the framework seems to compile normally.
So the question is: How can I make Xcode generate the swift bridging header to the right place, and how to remove it from the public headers folder.
Clean, Rebuild, DerivedData-Nuke didn't help.

Related

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?
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
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.
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.
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.
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.

Swift objects not visible only when compiling to a tvOS target

So I've got an application with multiple targets, some iOS and some tvOS. It's originally written in Objective-C, but we write any new functionality/code in Swift.
The problem is that when building for a tvOS target, the Swift classes don't get added to the -Swift.h file (the one that is generated when building a project with both Objective-C and Swift source files) properly. Thus, the Objective-C code doesn't recognize the Swift classes, and I get build errors.
The project builds fine, and all Swift classes are visible when building an iOS target.
Do any of you have any idea as to what might be causing this?
I figured it out. Evidently, even though the system does create a -Swift.h file, it won't actually bridge the classes unless the Objective-C-Bridging-Header.h has a value pointing to a bridging header in the project, despite the fact that the Objective-C Generated Interface Header Name plist key had a value. It would generate the Swift bridging header just fine--it just wouldn't actually do any of the bridging.

Adding sub-project in swift

I have 2 projects in a workspaces, both are built using Swift.
I want to use one of the project as a sub-project of the other one and the classes, which are in the sub-project, in the parent project.
My sub-project is using bridging-header.
I have tried to add one project as a reference to another and imported the class, which is in sub-project, but it didn't work.
Showing me Error: "No such module "
Please help me achieving this?
Fixed the issue, thing i did was:
Removed bridging header file, which was bridging my objective-C and
swift code from my framework and deleted the bridging header file from Build Settings.
Created a file named "Framework-name.h" and copied all the header files, which were there in my bridging header file, into "Framework-name.h" file.
import "Framework-name.h" inside "Framework-name.h" file (this is vey important, it will keep the file at the root level of the framework).
Made "Framework-name.h" and files that were included in Framework-name.h" file public.
Created an aggregate target for my framework. https://medium.com/#syshen/create-an-ios-universal-framework-148eb130a46c
Built the framework.
Drag and drop the created framework into the root level of another sample project.
Test the framework, writing import Framework-name in swift class of the sample project.
Build the project.
Bingo!!!

Can't include Objective C Files into Project?

I want to include an Objective-C project (https://github.com/soffes/ssziparchive) into my Swift Project so that I can include the SSZipArchive into my project. I need this so I can unzip a file. As included in the instructions on the Github, I included the folder minizip, SSZipArchive.h, and SSZipArchive.m into my project. I have also created a bridging header where I included the following import into my project #import "SSZipArchive.h". However, when I try to type SSZipArchive on Xcode, the autocomplete doesn't occur, leading me to believe that SSZipArchive isn't included properly in my project. Any ideas on how to do so? I have already looked at numerous links on how to include Objective-C projects into Swift and I have found that I simply need to include the corresponding header files for my project to work.
I guess that you haven't set bridging header path properly. It's a very common problem, but easy one to fix.
Go to the Project Settings -> Build Settings -> Search, and search for bridg, and under Objective-C Bridging Header set the path of your bridging header file (carefully inspect it's path in Finder first, since it may be in some sub-directory of your project).
Also make sure that all your included header files have target of your application. To check if they have, click on the header file, open up Utilities from the right side and under Target Membership, make sure the first target is checked.

Adding frameworks to Xcode project

I have added a framework to xcode project. Under Build phases->Link Binary With Libraries.
The framework consists of a library file (.a file) and a folder "Headers" which includes all the necessary header files for that framework.
Now I am trying to import a header file in the framework to one of my classes.
#import <MySDK/MyHeaderFile.h>
But an error occurs "Symbol not found" while building.
My understanding was that, if we are using framework instead of library file there is no need to add the header files path in "Header Search Path".
But still, I have specified the path to my framework in header search path.
Also I have specified the framework path in Framework search and Library Search path options.
This is first time I am working with frameworks. For libraries I just added the .a files and specified full path to header files in header search path.
What configuration am I missing for adding frameworks?
If it's a static library file and a bunch of headers, it's not a framework. A framework is a specific method of packaging files. On MacOS X static and dynamic frameworks have one structure, while static frameworks on iOS have a different structure.
For a static framework using Xcode 5, your file structure would look like this:
MySDK.framework/
en.lproj/
Headers/
MyHeaderFile.h
Info.plist
MySDK
Where MySDK is the binary archive file (it should not be MySDK.a). If you have a file ending in .a , you have a static library rather than a framework. Building a static framework using Xcode 5 isn't easy but it is also not impossible. Building a static library is much, much easier and trouble free however. It sounds like you already have a static library, so you just have to tell Xcode where to find the library archive and header files using the appropriate search path settings for your project or target.
If/when you DO have a framework, adding it to "Link libraries and frameworks" OR setting "Other linker flags" to "-framework path/to/MySDK.framework" will work fine.
Newer versions of Xcode may support different functionality for building or using frameworks, however linking against them should be largely the same.
MySDK/MyHeaderFile.h : This explains that your library is inside MySDK folder. Check if it exists in same path. Otherwise you'll get "Symbol Not Found" error.

Resources