Objective-C类中的Swift协议

时间:2022-09-07 08:51:33

I wrote SearcherProtocol in Swift and need to implement an Objective-C class FileSearcher which has to use this protocol.

我用Swift编写了SearcherProtocol,需要实现一个Objective-C类文件查找器,它必须使用这个协议。

So I tried this:

所以我试着:

#import <Foundation/Foundation.h>

@interface FileSearcher : NSObject <SearcherProtocol>

// ... class content

@end

The compiler tells me

编译器告诉我

Cannot find protocol declaration for 'SearcherProtocol'

无法找到“SearcherProtocol”的协议声明

The corresponding bridged header file (modulename-Swift.h) is being imported within FileSearcher.m.

在FileSearcher.m中导入相应的桥接头文件(modul珐琅- swift .h)。

Importing SearcherProtocol into FileSearcher.h throws another compiler error: module name-swift.h file not found

进口SearcherProtocol FileSearcher。h抛出另一个编译器错误:模块名称-swift。h文件未找到

Does anybody have any clue what I'm doing wrong?

有人知道我做错了什么吗?

I'm using Xcode 6 Beta 5.

我用的是Xcode 6 Beta 5。

Edit

编辑

Here is the protocol declaration in Swift:

以下是Swift的议定书声明:

@objc protocol SearcherProtocol
{    
    var searchNotificationTarget: SearchCompletedProtocol? { get }
    var lastSearchResults: [AnyObject] { get set }

    func search(searchParam: String, error: NSErrorPointer) -> Bool
}

And the SearchCompletedProtocol:

SearchCompletedProtocol:

@objc protocol SearchCompletedProtocol
{
    func searchCompletedNotification(sender: AnyObject!)
}

6 个解决方案

#1


29  

There are two common reasons for this occuring:

出现这种情况有两个常见原因:

  1. Getting the module name wrong, see my answer.
  2. 模块名称错误,请参见我的答案。
  3. Having a circular reference - see mitrenegades answer below.
  4. 有一个循环引用-见下面米特维迪斯的回答。

1. Get the module name right:

1。正确获取模块名称:

If both the swift protocol and and Objective C are in the same project then according to apple you should just need to make sure you get the correct module name.

如果swift协议和Objective - C都在同一个项目中,那么根据apple的说法,您只需确保获得正确的模块名。

For Xcode6 beta 5 you can find it under BuildSettings->Packaging->Product Module Name

对于Xcode6 beta 5,您可以在BuildSettings—>打包—>产品模块名称下找到它

A common mistake would be to think that each swift file/class gets its own file, but instead they are all put into one big one that is the name of the project.

一个常见的错误是认为每个swift文件/类都有自己的文件,但是它们都被放在一个大文件中,这就是项目的名称。

A further mistakes are if the module name has spaces, these should be replaced with underscores.

另一个错误是,如果模块名有空格,则应该用下划线替换。

Edit:

编辑:

With your protocol I created a test project called 'Test' which compiles perfectly and it has the files:

在你的协议中,我创建了一个名为“测试”的测试项目,它编译得很完美,并且有文件:

TestObjClass.h

TestObjClass.h

#import <Foundation/Foundation.h>
#import "Test-Swift.h"

@interface TestObjCClass : NSObject <SearcherProtocol>

@end

TestObjClass.m

TestObjClass.m

#import "TestObjCClass.h"


@implementation TestObjCClass

@end

TestProtocol.swift

TestProtocol.swift

import Foundation

@objc protocol SearcherProtocol
{
    var searchNotificationTarget: SearchCompletedProtocol? { get }
    var lastSearchResults: [AnyObject] { get set }

    func search(searchParam: String, error: NSErrorPointer) -> Bool
}

@objc protocol SearchCompletedProtocol
{
    func searchCompletedNotification(sender: AnyObject!)
}

2. Avoid circular reference:

2。避免循环引用:

Mitrenegades answer explains this, but if your project needs to use the explicit objc class that uses the swift protocol, (rather than just using the protocol) then you will have circularity issues. The reason is that the swift protocol is defined to the swift-objc header, then to your obj-c class definition, which then goes again to the swift-objc header.

Mitrenegades解释了这一点,但是如果您的项目需要使用使用swift协议的显式objc类(而不仅仅是使用协议),那么您就会遇到循环问题。原因是swift协议定义为swift-objc头,然后定义为object -c类,然后再定义为swift-objc头。

Mitrenegades solution is to use an objective-c protocol, is one way, but if you want a swift protocol, then the other would be to refactor the code so as to not use the objective-c class directly, but instead use the protocol (e.g. some protocol based factory pattern). Either way may be appropriate for your purposes.

Mitrenegades解决方案是使用objective-c协议,这是一种方法,但是如果您想要一个swift协议,那么另一种方法是重构代码,以便不直接使用objective-c类,而是使用协议(例如,一些基于协议的工厂模式)。任何一种方式都可能适合您的目的。

#2


18  

When you have

当你有

#import "moduleName-Swift.h" 

in the .h file that you want to be a delegate, and you have that .h file also in the bridging headers file, there's a circular reference that causes the moduleName-Swift.h to fail compilation. for @james_alvarez's test project, it's probably working because you don't need to include TestObjClass.h into the bridging header.

在你想要成为委托的。h文件中,在桥接头文件中也有。h文件,有一个循环引用,它导致了模块化- swift。h编译失败。对于@james_alvarez的测试项目,它可能是有效的,因为您不需要包含TestObjClass。h进入桥接头。

The best way for me to combine objc files that need to be the delegate for a class written in swift, but that also needs to be included in the bridging header so other swift files can access this objc class, is to create a separate protocol file in objc:

对我来说,合并objc文件的最佳方式是在objc中创建一个单独的协议文件,这个文件需要是swift编写的类的委托,但是也需要包含在桥接头中,以便其他swift文件可以访问这个objc类:

MyProtocol.h:

MyProtocol.h:

@protocol MyDelegate <NSObject>

-(void)didDoThis;
-(void)didDoThat;

@end

ViewController.h:

ViewController.h:

#import "MyProtocol.h"

@interface ViewController : UIViewController <MyDelegate>

MyProject-Bridging-Header.h

MyProject-Bridging-Header.h

#import "MyProtocol.h"
#import "ViewController.h"

#3


16  

I know this was a long time ago, but I just struggled with the same problem when adding a protocol to my Swift code, and it wasn't being added to the -Swift.h header file, hence "Cannot find protocol declaration"

我知道这是很久以前的事了,但是当我在我的Swift代码中添加一个协议时,我遇到了同样的问题,而且它没有被添加到-Swift中。h头文件,因此“无法找到协议声明”

The problem was my protocol wasn't marked as Public. I changed my protocol from this:

问题是我的协议没有被标记为公开。我改变了我的习惯

@objc protocol MyProtocol { //etc.... }

to this:

:

@objc public protocol MyProtocol { //etc.... }

I'm still not entirely sure why I need 'Public' but nobody else seems to, but hey it works...

我仍然不完全确定为什么我需要“公众”,但似乎没有人需要,但嘿,它起作用了……

#4


1  

Make sure you are including the auto generated Swift header in your ObjectiveC file. It will have the same name as your project module followed by -Swift.h.

确保在objective - vec文件中包含自动生成的Swift标头。它将具有与项目模块相同的名称,后跟-Swift.h。

For instance if your Project Module is MyTarget, then you would use:

例如,如果您的项目模块是MyTarget,那么您将使用:

#import "MyTarget-Swift.h"

#进口“MyTarget-Swift.h”

If you are typing in the import into your Objective C file, it will not autocomplete. You can verify that you have the correct file by Command-clicking on the header after typing it in.

如果您在目标C文件中输入导入,它将不会自动完成。输入文件后,您可以通过命令单击标题来验证文件是否正确。

#5


-2  

Import delegate as like this in .h file

在.h文件中像这样导入委托

@protocol AnalyticProtocol;

and add this in to .swift file

并将其添加到。swift文件中

@objc public protocol AnalyticProtocol {

}

#6


-3  

Try adding #import "Product_Module_Name-Swift.h" to your Product_Module_Name-Prefix.pch file. That fixed it for me, plus you will now have access to your swift files from any objc file.

尝试添加# Product_Module_Name-Swift进口”。Product_Module_Name-Prefix h”。pch文件。这为我修复了它,另外你现在可以从任何objc文件访问你的swift文件。

#1


29  

There are two common reasons for this occuring:

出现这种情况有两个常见原因:

  1. Getting the module name wrong, see my answer.
  2. 模块名称错误,请参见我的答案。
  3. Having a circular reference - see mitrenegades answer below.
  4. 有一个循环引用-见下面米特维迪斯的回答。

1. Get the module name right:

1。正确获取模块名称:

If both the swift protocol and and Objective C are in the same project then according to apple you should just need to make sure you get the correct module name.

如果swift协议和Objective - C都在同一个项目中,那么根据apple的说法,您只需确保获得正确的模块名。

For Xcode6 beta 5 you can find it under BuildSettings->Packaging->Product Module Name

对于Xcode6 beta 5,您可以在BuildSettings—>打包—>产品模块名称下找到它

A common mistake would be to think that each swift file/class gets its own file, but instead they are all put into one big one that is the name of the project.

一个常见的错误是认为每个swift文件/类都有自己的文件,但是它们都被放在一个大文件中,这就是项目的名称。

A further mistakes are if the module name has spaces, these should be replaced with underscores.

另一个错误是,如果模块名有空格,则应该用下划线替换。

Edit:

编辑:

With your protocol I created a test project called 'Test' which compiles perfectly and it has the files:

在你的协议中,我创建了一个名为“测试”的测试项目,它编译得很完美,并且有文件:

TestObjClass.h

TestObjClass.h

#import <Foundation/Foundation.h>
#import "Test-Swift.h"

@interface TestObjCClass : NSObject <SearcherProtocol>

@end

TestObjClass.m

TestObjClass.m

#import "TestObjCClass.h"


@implementation TestObjCClass

@end

TestProtocol.swift

TestProtocol.swift

import Foundation

@objc protocol SearcherProtocol
{
    var searchNotificationTarget: SearchCompletedProtocol? { get }
    var lastSearchResults: [AnyObject] { get set }

    func search(searchParam: String, error: NSErrorPointer) -> Bool
}

@objc protocol SearchCompletedProtocol
{
    func searchCompletedNotification(sender: AnyObject!)
}

2. Avoid circular reference:

2。避免循环引用:

Mitrenegades answer explains this, but if your project needs to use the explicit objc class that uses the swift protocol, (rather than just using the protocol) then you will have circularity issues. The reason is that the swift protocol is defined to the swift-objc header, then to your obj-c class definition, which then goes again to the swift-objc header.

Mitrenegades解释了这一点,但是如果您的项目需要使用使用swift协议的显式objc类(而不仅仅是使用协议),那么您就会遇到循环问题。原因是swift协议定义为swift-objc头,然后定义为object -c类,然后再定义为swift-objc头。

Mitrenegades solution is to use an objective-c protocol, is one way, but if you want a swift protocol, then the other would be to refactor the code so as to not use the objective-c class directly, but instead use the protocol (e.g. some protocol based factory pattern). Either way may be appropriate for your purposes.

Mitrenegades解决方案是使用objective-c协议,这是一种方法,但是如果您想要一个swift协议,那么另一种方法是重构代码,以便不直接使用objective-c类,而是使用协议(例如,一些基于协议的工厂模式)。任何一种方式都可能适合您的目的。

#2


18  

When you have

当你有

#import "moduleName-Swift.h" 

in the .h file that you want to be a delegate, and you have that .h file also in the bridging headers file, there's a circular reference that causes the moduleName-Swift.h to fail compilation. for @james_alvarez's test project, it's probably working because you don't need to include TestObjClass.h into the bridging header.

在你想要成为委托的。h文件中,在桥接头文件中也有。h文件,有一个循环引用,它导致了模块化- swift。h编译失败。对于@james_alvarez的测试项目,它可能是有效的,因为您不需要包含TestObjClass。h进入桥接头。

The best way for me to combine objc files that need to be the delegate for a class written in swift, but that also needs to be included in the bridging header so other swift files can access this objc class, is to create a separate protocol file in objc:

对我来说,合并objc文件的最佳方式是在objc中创建一个单独的协议文件,这个文件需要是swift编写的类的委托,但是也需要包含在桥接头中,以便其他swift文件可以访问这个objc类:

MyProtocol.h:

MyProtocol.h:

@protocol MyDelegate <NSObject>

-(void)didDoThis;
-(void)didDoThat;

@end

ViewController.h:

ViewController.h:

#import "MyProtocol.h"

@interface ViewController : UIViewController <MyDelegate>

MyProject-Bridging-Header.h

MyProject-Bridging-Header.h

#import "MyProtocol.h"
#import "ViewController.h"

#3


16  

I know this was a long time ago, but I just struggled with the same problem when adding a protocol to my Swift code, and it wasn't being added to the -Swift.h header file, hence "Cannot find protocol declaration"

我知道这是很久以前的事了,但是当我在我的Swift代码中添加一个协议时,我遇到了同样的问题,而且它没有被添加到-Swift中。h头文件,因此“无法找到协议声明”

The problem was my protocol wasn't marked as Public. I changed my protocol from this:

问题是我的协议没有被标记为公开。我改变了我的习惯

@objc protocol MyProtocol { //etc.... }

to this:

:

@objc public protocol MyProtocol { //etc.... }

I'm still not entirely sure why I need 'Public' but nobody else seems to, but hey it works...

我仍然不完全确定为什么我需要“公众”,但似乎没有人需要,但嘿,它起作用了……

#4


1  

Make sure you are including the auto generated Swift header in your ObjectiveC file. It will have the same name as your project module followed by -Swift.h.

确保在objective - vec文件中包含自动生成的Swift标头。它将具有与项目模块相同的名称,后跟-Swift.h。

For instance if your Project Module is MyTarget, then you would use:

例如,如果您的项目模块是MyTarget,那么您将使用:

#import "MyTarget-Swift.h"

#进口“MyTarget-Swift.h”

If you are typing in the import into your Objective C file, it will not autocomplete. You can verify that you have the correct file by Command-clicking on the header after typing it in.

如果您在目标C文件中输入导入,它将不会自动完成。输入文件后,您可以通过命令单击标题来验证文件是否正确。

#5


-2  

Import delegate as like this in .h file

在.h文件中像这样导入委托

@protocol AnalyticProtocol;

and add this in to .swift file

并将其添加到。swift文件中

@objc public protocol AnalyticProtocol {

}

#6


-3  

Try adding #import "Product_Module_Name-Swift.h" to your Product_Module_Name-Prefix.pch file. That fixed it for me, plus you will now have access to your swift files from any objc file.

尝试添加# Product_Module_Name-Swift进口”。Product_Module_Name-Prefix h”。pch文件。这为我修复了它,另外你现在可以从任何objc文件访问你的swift文件。