131

I try to import a Swift Protocol named AnalyticProtocol into an Objective-C class named AnalyticFactory.

protocol AnalyticProtocol
{

}

I'm starting from an existing Objective-C project (I didn't create a new Swift project with xCode and I didn't found how configure my Objective-C project to be a Swift project in xCode 6).

In my Swift file I included the .h file named MyProjectName-Swift.h but the compiler return me an error telling me that it doesn't exist. So, I created a .h file named MyProjectName-Swift.h which is actually empty (I don't know what I should put inside).

In the Apple documentation they said that I have to include my .h file named MyProjectName-Swift.h in my .m file. But I need to include it not into my .mfile but into my .h. Does this can be problematic?

When I try to compile I've got this error: :0: error: xxxAnalyticFactory.h:39: cannot find protocol declaration for 'AnalyticProtocol'

And the incriminated code:

@interface AnalyticFactory : NSObject
{
    Class<AnalyticProtocol> _analyticProtocolClass; // The type of the analytic class currently used.
}

I think I don't understand well how can I import a Swift protocol into an Objective-C class.

Does anyone see an error in what I'm doing?

Michael Currie
  • 13,721
  • 9
  • 42
  • 58
Jean Lebrument
  • 5,079
  • 8
  • 33
  • 67
  • Check out the [_Integrating Swift With Objective-C_](http://devstreaming.apple.com/videos/wwdc/2014/406xxssvkspk997/406/406_hd_integrating_swift_with_objective_c.mov?dl=1) video from WWDC 2014. At around 30:40 into the video, they describe how to access Swift protocols in Objective-C classes. – Jamie Forrest Jun 06 '14 at 12:07

5 Answers5

241

You need to add the @objc attribute to your Swift protocol like so:

@objc protocol AnalyticProtocol {

}
Jamie Forrest
  • 10,895
  • 6
  • 51
  • 68
  • 30
    Thanks for your answer but the problem still persists. – Jean Lebrument Jun 06 '14 at 12:42
  • Could you maybe post a sample project that reproduces the issue? – Jamie Forrest Jun 06 '14 at 14:40
  • Adding @objc helped me with importing Swift classes in to Obj-C – ssoldatenkov Jun 13 '14 at 09:01
  • 22
    @objc doesn't always work. When conforming to a protocol sometimes it doesn't work when adding the protocol on the `@interface` in the `.h` file. however, you can add the protocol to the private `@interface` in the `.m` file and it fixes things (at least it has for me on occasion). So above your `@implementation` have `@interface MyController() `. – Adam Oct 05 '15 at 19:36
  • 1
    Sometimes Xcode 8 will complain while you are editing, but when you actually build it, following this answer along with the comments, the error will go away. – Roger Pingleton Oct 09 '16 at 21:37
  • You also need to add `@objc` in protocol methods in order to them useable in Objective-C i.e `@objc func foo()` – Khurram Shehzad Feb 29 '20 at 11:07
89

It is not possible to import the Xcode generated Swift header in objC header files.

So, since you want to use Swift code in an objC header file, you will need to "forward declare" the classes and protocols you want to use in the objC header file, like this:

@protocol AnalyticProtocol;

You can now use the protocol in your objC class declaration:

@interface AnalyticFactory : NSObject
{
    Class<AnalyticProtocol> _analyticProtocolClass; // The type of the analytic class currently used.
}

In your implementation file (the objC .m file), you can import the Xcode generated Swift header ("ProductModuleName-Swift.h") file and the correct implementation AnalyticProtocol will now be known to the compiler.

This is also described in official Importing Swift into Objective-C

Note that XCode will give a warning in the objC header file when you use the forward declared protocol ("Cannot find protocol definition for 'AnalyticProtocol'), but this is can be ignored - the implementation will be found at compile time.

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
Pelle Stenild Coltau
  • 1,268
  • 10
  • 15
  • 20
    Why does Xcode show the warning for missing protocol when it compiles and works fine? Any way to remove the warning? – Oren Jul 02 '15 at 05:52
  • 1
    It's still not possible to call the protocol methods on this class though. It will give the error ```No visible @interface for declares the selector ``` – Elsa Aug 22 '18 at 08:13
  • it produces the following warning: "Cannot find protocol definition for xxxx" – JAHelia Feb 04 '19 at 19:09
58

For anybody who simply needs to adopt a protocol – you can do this in two steps, without generating any warnings or errors:

  1. In your .swift file, add @objc before the protocol name:

    @objc protocol AnalyticProtocol {
    
    }
    
  2. In your .m file, import the generated Swift header and adopt the protocol in a private category. (The header file is named automagically):

    #import "ProductModuleName-Swift.h"
    
    @interface AnalyticFactory () <AnalyticProtocol>
    
    @end
    

This is Apple’s recommended approach. You can learn more about mixing and matching Objective-C and Swift here: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

Chris Nolet
  • 8,714
  • 7
  • 67
  • 92
  • 1
    I still get a warning, with forward declaration or without. I'm using the protocol in an extension. – Cristi Băluță May 26 '17 at 08:56
  • Cannot import `#import "AnalyticProtocol-Swift.h"`. Looks like that WhateverProtocol-Swift.h is not auto-generated as you said. – Hlung Nov 20 '17 at 10:36
  • Thanks for your comments! I have updated my answer with Apple’s latest recommended approach. There are now no warnings. – Chris Nolet Apr 25 '18 at 18:25
  • 3
    This worked for me; no other suggestions or answers on this page worked. I'm on Swift 4. – Poulsbo Jun 07 '18 at 05:40
  • 1
    This was the only way to remove the warning (even though it works when the protocols are in the header file) – David P Jun 27 '18 at 01:16
  • IT'S NOT TRUE, recommended or not, there is other warning if you have this "fixed" class in typed array based on that protocol, compiler generates other warning, quite logically, because its not in header now.. looks like this is not possible to do warning less... – Renetik Nov 22 '18 at 07:04
  • 2
    This did indeed get rid of the warning for me, but then the compile has errors, because a swift class that uses the ObjC file that adopts the Swift protocol can't see that the ObjC file is adopting the protocol! – occulus Feb 04 '19 at 11:20
  • The link is dead! – Richard Topchii Jun 17 '19 at 14:46
  • 2
    The same link is available via WebArchive: https://web.archive.org/web/20170310053717/https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html – Richard Topchii Jun 17 '19 at 14:49
  • 1
    Note: If you're still getting a build warning with this approach, make sure the protocol is not forward-declared in the ObjC .h file. Additionally, you can't mark the class as conforming to the protocol in the header file. As long as the protocol appears only in .m, you'll be all set. – Bryan Sep 28 '19 at 23:18
  • a possible approach to actually solve this issue using this solution is to expose a member on the class that adopts the protocol in the .h file while forward declaring the protocol.then return self in the implementaiton – Nadav matityahu Jan 25 '22 at 13:01
9

We can use swift protocols in Objective C with few changes to the code. Also, @objc declared protocols let you have optional and required methods without default implementations. It comes with pros and cons.

We could actually re-name the protocol name to a more descriptive when using in Objective C. I make use of "@objc(alias_name)".

Here is the code, Let's have a swift protocol with @objc attribute and alias name to use in the ObjC code.

@objc(ObjTableViewReloadable) protocol TableViewReloadable: class {
   func reloadRow(at index: IndexPath)
   func reloadSection(at index: Int)
   func reloadTable()
}

Now lets farword declare our protocol in .h file

@protocol ObjTableViewReloadable;

You can now conform to this protocol in .m file and add required methods implementation.

#import "MyApp-Swift.h"
@interface MyObjcViewController () <ObjTableViewReloadable>
Vinay Hosamane
  • 346
  • 1
  • 5
  • 15
  • Thank you for posting this. I'm looking at legacy code that's older than dirt and if this approach works, it will save me a ton of pain. :) – Adrian Apr 02 '20 at 21:11
  • Hi, what is the header MyApp-Swift.h ? is the swift class header generated for Objc that contains the protocol? – Coder Jul 28 '21 at 10:12
5

If your are creating a framework, the required import

#import "ProductModuleName-Swift.h"

changes to:

#import <ProductModuleName/ProductModuleName-Swift.h>

In this case you also must make the swift protocol public:

@objc public protocol AnalyticProtocol {
  func something();
}
Michal
  • 4,846
  • 3
  • 33
  • 25