Include -Swift.h in the umbrella header - ios

I have a mixed Swift and Objective-C project. To access a Swift public API in Objective-C, the API consumer currently has to import "MyModule-Swift.h". I already have a Objective-C umbrella header called "MyModule.h". But, importing "MyModule.h" is not going to work for the Swift APIs. I tried importing "MyModule-Swift.h" in the umbrella header, but it doesn't find it (I'm assuming since it is generated on the fly by Xcode).
Any suggestions so that an API consumer can always import "MyModule.h" to use public APIs written in Swift/Objective-C will be really appreciated.
====================================================================
Edit: I apologize for not taking the time to properly frame the question. I have a framework called MyModule.
I have a Objective-C class called ABUser,
#interface ABUser: NSObject
- (void)walk;
#end
I wanted to add new behavior to this class using Swift, so I defined an extension
extension ABUser {
func swiftWalk()
}
Now, say I wanted to access the swiftWalk method defined on ABUser from an Objective-C app, I would have to #import <MyModule/MyModule-Swift.h>. #import <MyModule/MyModule.h> would work if I wanted to use the walk method. This is assuming the umbrella header MyModule.h imports ABUser.h.
I always wanted the Objective-C app to #import <MyModule/MyModule.h> and never have to worry about whether an API was written in Objective-C or Swift in the framework. So, I tried importing MyModule-Swift.h in the umbrella header MyModule.h. But, my Objective-C app didn't compile if do that. Not sure, if this is because MyModule-Swift.h is generated by Xcode on the fly during the build process.
Edit 2: Added a sample project to reproduce this issue here: https://github.com/priteshshah1983/MyObjectiveCApp
The relevant code is in ViewController.m. The build will fail with the master branch. To get it work, checkout the working branch.

The reason that using #import MyModule; worked, is that "modules are a packaging together of the framework executable and it's headers" (from this SO post).
In other words, when you #import MyModule;, Objective-C automatically imports all the swift and Objective-C headers related to the module, while you cannot include the swift header from the umbrella header. I suggest you take a look at the differences between #import and #import in the linked SO answer.

It turns out that using #import MyModule; instead of #import <MyModule/Module.h> allows using walk and swiftWalk methods as expected from the Objective-C app.
I honestly don't understand the details, but I hope this helps someone else. Please feel free to explain!

Related

myProjectName-Swift.h not found after clean build

Spent a lot of time on finding the solution on google and SO but no success. Very hope someone can point out what can be the problem.
So I have objc+swift project. I have a Bridging Header file with imports of Objc header files that I need to use in Swift.
To explain the issue I'll share 2 scenarios. In the 1st scenario, everything works fine. In 2nd it shows an error.
Please note: Both scenarios have the same code base.
Scenario 1. Doesn't work, shows error.
I open the project.
Hard Clean it.
Build
Shows error: 'myProjectName-Swift.h' file not found
It also shows such error:
failed to emit precompiled header
'/Users/tungfam/Library/Developer/Xcode/DerivedData/myProjectName-ctxxkwqtckhvyoawavmuzmdxqaml/Build/Intermediates.noindex/PrecompiledHeaders/myProjectName-Bridging-Header-swift_1UP5PCPCLBPHP-clang_18PVO5108TD8S.pch'
for bridging header
'/Users/tungfam/Developer/myProjectName/myProjectName/App/myProjectName-Bridging-Header.h'
Scenario 2. How to make it work.
I take the same code from Scenario 1.
Hard Clean it
Comment the imports in Bridging Header file
Comment the Swift code where I used Obc files (that were declared in bridging header that I just commented in previous step)
I build the project. It succeeds.
Since some parts in the app are broken cuz I commented stuff. I uncomment the imports in Bridging Header file and the Swift code where I used Objc classes.
Run again (without hard clean) and everything works.
Will really appreciate any help on this issue. Please share anything you think that may help to fix this issue.
I'm using Xcode 10.0; Swift 4.2
UPDATE1: I think it has to do something with the 2nd error I placed above. Maybe it can't generate that bridging file.
UPDATE2: I read something like: "If you are importing the Objc file named ABC into Bridging Header. And if this ABC imports into himself the file myProjectName-Swift.h. Then this case may have some problems. Do you think it can be true?
You must not use #import "ProjectName-Swift.h" in the header files.
If you need Swift classes or protocols in the Obj-C code, you may forward declare them in the related Obj-C header. Here's more information about that:
When declarations in an Objective-C header file refer to a Swift class or protocol that comes from the same target, importing the generated header creates a cyclical reference. To avoid this, use a forward declaration of the Swift class or protocol to reference it in an Objective-C interface.
// MyObjcClass.h
#class MySwiftClass;
#protocol MySwiftProtocol;
#interface MyObjcClass : NSObject
- (MySwiftClass *)returnSwiftClassInstance;
- (id <MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol;
// ...
#end
Also, please note, you may have issues with importing Swift Enums and Protocols and Classes into ObjC, so you may need to explicitly define items which you want to be available to ObjC code with #objc keyword.
And you won't be able to use Swift structs in Obj-C.
From Swift to Objective C you just have to use #import "ProjectName-Swift.h" on your Objective C classes that needs access to Swift code. There's no need to add on the bridging header file. For the other way Objective C to Swift then you need to declare in the bridging header file.

How to use an Obj-c Library/Custom interface in a Swift Project

Trying to understand how I can use this in my swift project.
https://github.com/Grouper/FlatUIKit
I have copied the classes folder into my project but am not sure how to use the various .h and .m files. How would I go about using these files within my storyboard to use the custom appearances?
Did some searching and wasn't really able to understand the various threads that I found.
A bit of a broad question so I'll try to provide some basics and hopefully that helps.
If you are unaware, there is a whole book written by Apple about how to use objective-c with swift. it's available on iBooks for free Using Swift with Cocoa and Objective-C (Swift 2.1) by Apple Inc
Here is the online link
You will need to create an objective-c bridging header and import your code through the header.
Your bridging header would look like this:
#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import "XYZCustomViewController.h"
If they don't have any modules then you can use them in your swift code and it should see them. According to Apple:
Use your custom Objective-C code with the same Swift syntax you use with system classes.
let myCell = XYZCustomCell()
myCell.subtitle = "A custom cell"
If you are importing an Objective-c framework then it should already contain and umbrella header file that takes care of the bridging header stuff for you. then you just import the framework name into the class that you are planning on using.
import MyCustomFramework
Link to the apple docs here
For this, you can use a bridging header, which is used to expose Objective C code to swift. To do this, make a new header file in your project. Import the header files you would like to use in the new header file like this:
#import <FlatUIKit/FlatUIKit.h>
And then, in the build settings of your project, define the Objective-C bridging header to be the header file you just created. Now in any swift files that you would like to use the library in just import the classes like this:
import FlatUIKit
Hope this helps!

Swift class in Cocoa Touch Objective-C Framework

I'm trying to build a Cocoa Touch Framwork (XCode 6, obviously) with Objective-C and some Swift classes.
I've successfully added Swift classes to regular projects (no framworks) before so I'm aware of the build settings required for this (Embedded Content Contains Swift Code). Unfortunately, the framework project doesn't build the header file (projectName-Swift.h) and I'm not able to import the class and the Swift classes into any of my .m files.
Does anybody know why this wouldn't work, and what build settings I need to change in order to make this work?
Finally found the answer;
Within the frameworks the import statement for Swift files has to look as follows;
#import <ProjectName/ProjectName-Swift.h>
instead of
#import "ProjectName-Swift.h"
Sometimes it helps to RTFM (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_82)
I've struggled with this for a while because I don't think the documentation is clear. I have a slightly different project setup, and it's taken me a while to work this out so I thought I'd answer here.
I have a project with name: MyProject
In this project, I have a framework: MyFramwork
I have a swift file in MyFramework which I want to import into an objective c file in MyFramework.
To do this, you need:
#import <MyFramework/MyFramework-Swift.h>
NOT
#import <MyProject/MyFramework-Swift.h>
Hope that helps someone.

Mixed language framework

I have a framework (let's call it MyKit) written in Objective-C that I'm extending with some Swift classes. I'm trying to get my head around it using this documentation: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_77
As far as I understand, I'm not supposed to have a bridging header class, and instead put all my includes in the umbrella header file (that I understand to be ).
So I write in MyKit.h:
#import <MyKit/ModelObjectA.h>
#import <MyKit/ModelObjectB.h>
#import <MyKit/ControllerObjectC.h>
I don't list ControllerObjectD.swift, even though it goes into here as well? Or should I include
#import <MyKit/ControllerObjectD-Swift.h>
?
ControllerObjectD uses ModelObjectA and ModelObjectB. Now that I don't have a bridge headerfile, I get compile errors in it because it cannot find these objects.
The documentation says "Swift will see every header you expose publicly in your umbrella header." and this is true when I import the framework into other projects, but the framework project cannot compile because it doesn't see it. I have turned on the "Define Modules" build setting.
Is there something I've misunderstood about the umbrella header, perhaps? Where can I say "hi project, this is the umbrella header file"? The framework compiles if I set the umbrella header file as bridging header, but that sounds like I've come back to the beginning this way?
Cheers
Nik
I believe your problem may be down to the Access Modifiers in your Swift class, however I've written a short guide and sample project to help you:
Sample project can be found here
There are two parts to having a mixed language framework:
Importing Objective-C into Swift
Importing Swift into Objective-C
1. Importing Objective-C into Swift
This is, for example, if you have an Objective-C class named Player that you want to add to a swift class called Game.
According to the documentation, you need to do these two steps to import the Player object into the Game object.
Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to Yes.
In your umbrella header file, import every Objective-C header you want to expose to Swift.
#import <Framework/Player.h>
Make sure your Player header file in Objective-C is marked for public target membership in the framework:
Following these steps, it's possible to import the Player Objective-C class into the Game Swift Class:
import UIKit
public class Game: NSObject {
public let player: Player
public init(player: Player) {
self.player = player
super.init();
}
}
2. Importing Swift into Objective-C
For importing the Swift Game class into the Player object, we can follow a similar procedure.
As before; Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to Yes.
Import the Swift code from that framework target into any Objective-C .m file within that framework target using this syntax and substituting the appropriate names:
#import <ProductName/ProductModuleName-Swift.h>
In my case, this works as:
#import <SwiftObjC/SwiftObjC-Swift.h>
and I assume, for you:
#import <MyKit/MyKit-Swift.h>
Therefore, make sure that all the properties, methods and classes you want to access are defined as public in your swift file or else they won't be visible to Objective-C .
I have uploaded my sample project showing how this all works on GitHub https://github.com/elliott-minns/SwiftObjCTestFramework
I hope this helps you with your problem.
I think you need to do bridging-header to access your obj-c code in swift.
More in the link
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html
so it is a file with your imports from obj-c transfering to swift. names are very important so care about that. hope it helps
p.s. also you need to add this header path to your project settings
From the Documentation at Apple: A Swift class must be a descendant of an Objective-C class to be accessible and usable in Objective-C. For more information about what you can access from Objective-C and how the Swift interface is imported, see Swift Type Compatibility.
So your public swift class needs to extend NSObject for example.

Add MFSideMenu 3rd party library to swift project

I'm currently translating an Objective-C project I have over to Swift. In the process, I have a few implemented 3rd party libraries that are pure Objective-C like MFSideMenu and Parse.
I've created a Bridging-Header.h file per Apple's documentation and other's recommendations to bridge the Objective-C files with the Swift code. This works fine for frameworks like Parse. Unfortunately, when importing MFSideMenu and running the application, I receive the attached errors below.
I was contemplating if this was because a library needed to be manually imported into the Objective-C files using it, so I attempted importing UIKit and Foundation in the project and manually added the frameworks without any success. Any assistance would be greatly appreciated.
Turns out, the compiler for swift no longer supports non modular based imports for frameworks. You must change all references to frameworks to #import statements rather #import.
I had the same problem, add code below at the header file of this class
#import <UIKit/UIKit.h>
it can help you

Resources