14
votes

I have this code base which is Objective C and Swift mix. Some places Swift uses Objective and and vice versa. I need to create a framework now based of off this codebase but do not want to include all the objective c files in my umbrella header. Here's my problem:

Inside my framework I still need to be able to use swift from objc and vice versa; but do not want to expose all those objc files that are being used internally by swift classes. Bridging header is not allowed in frameworks so all the headers needed by swift need to go in umbrella header.

I'm wondering if it's possible to have all the objc headers needed by internal swift code go in a file which would be my private umbrella header and all the files that I need to expose would go in public umbrella header.

Any suggestions?

1
Hi, @puru020, have you found a solution for this? I have exactly the same problem and I can't find how to solve it. Thanks. - Daniel
I haven't. There doesn't seem to be a solution. What we decided to is to keep 2 sections in the umbrella header for public and private .h files. Once the framework is built we run a script that goes and deletes the private section of the umbrella header. - puru020
Yesterday I've been searching for hours to find solutions to this problem. The major problem is the restriction of not being able to use a bridging-header in frameworks. For the case "private objc-header in Swift", I stumbled upon the definition of a private module, a CLANG-feature. But unfortunately, this seems to be there for exposing private headers to other frameworks, rather than using private objc-headers in Swift. Though I believe there's a reason to the problems, as interoperability seems to be important to Apple. I would appreciate a clarifying answer. - Felix Lieb
If you need to completely hide those private .h files from users that will receive your framework then the only way to do it is to make them public (add them to public umrella header as usual) and remove them from the framework and from umbrella header after building it. You can do that by creating a special script in run script step added to the build process to make it automatic. - Leszek Szary

1 Answers

3
votes

I am successfully using explicitly declared modules as a solution of sorts for this issue for the Objective-C -> Swift case. I have not separated the module declaration into a separate private module map but declared both the framework module and an explicit module inside the same modulemap because of the concern raised in one of the comments to the question (I wasn't sure if or how it is possible to use the header generated by the private module map inside the same framework).

Here's an excerpt of the modulemap I have defined for my MPFoundation.framework, which includes an explicit module MPManuscriptCompiler_Protected that imports the header "MPManuscriptCompiler+Protected.h" which is not included in the umbrella header for the framework:

framework module MPFoundation {
    umbrella header "MPFoundation.h"

    export *
    module * { export * }

    explicit module MPManuscriptCompiler_Protected {
        header "MPManuscriptCompiler+Protected.h"
        export *
    }
}

I then use this explicit module MPManuscriptCompiler_Protected in my Swift subclass which is present in the same framework like so:

import MPFoundation.MPManuscriptCompiler_Protected

My solution is really technically just a workaround though: for this to work, "MPManuscriptCompiler+Protected.h" can be marked a private or project level header in the framework, so it will not be visible in the umbrella header and will not be available for header based imports with its filename. So, this works around having to include this header in the umbrella header.

However, the module created this way is publicly exposed in the framework and available for eyes that should not see it. I did not investigate this further as practically this solves the issue well enough (am yet to hit issues where I would have by accident imported that protected header where it wasn't supposed to be imported).