Протокол Swift в классе Objective-C
Я написал SearcherProtocol
в Swift и вам нужно реализовать класс Objective-C FileSearcher
, который должен использовать этот протокол.
Итак, я пробовал это:
#import <Foundation/Foundation.h>
@interface FileSearcher : NSObject <SearcherProtocol>
// ... class content
@end
Компилятор сообщает мне
Невозможно найти объявление протокола для "SearcherProtocol"
Соответствующий мостовой файл заголовка (modulename-Swift.h
) импортируется в пределах FileSearcher.m
.
Импортирование SearcherProtocol
в FileSearcher.h
вызывает другую ошибку компилятора: module name-swift.h file not found
Кто-нибудь знает, что я делаю неправильно?
Я использую Xcode 6 Beta 5.
Edit
Вот объявление протокола в Swift:
@objc protocol SearcherProtocol
{
var searchNotificationTarget: SearchCompletedProtocol? { get }
var lastSearchResults: [AnyObject] { get set }
func search(searchParam: String, error: NSErrorPointer) -> Bool
}
И SearchCompletedProtocol:
@objc protocol SearchCompletedProtocol
{
func searchCompletedNotification(sender: AnyObject!)
}
Ответы
Ответ 1
Для этого существуют две общие причины:
- Получение неправильного имени модуля, см. мой ответ.
- Имея круговую ссылку - см. ниже ответ на митенегаты.
1. Получить имя модуля правильно:
Если и быстрый протокол, и Objective C находятся в одном проекте, то в соответствии с apple вам просто нужно убедиться вы получите правильное имя модуля.
Для Xcode6 beta 5 вы можете найти его в разделе BuildSettings- > Packaging- > Product Module Name
Общей ошибкой было бы думать, что каждый быстрый файл/класс получает свой собственный файл, но вместо этого все они помещаются в один большой, который является именем проекта.
Другие ошибки заключаются в том, что если имя модуля имеет пробелы, они должны быть заменены символами подчеркивания.
Edit:
С вашим протоколом я создал тестовый проект под названием "Тест", который отлично компилируется и имеет файлы:
TestObjClass.h
#import <Foundation/Foundation.h>
#import "Test-Swift.h"
@interface TestObjCClass : NSObject <SearcherProtocol>
@end
TestObjClass.m
#import "TestObjCClass.h"
@implementation TestObjCClass
@end
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. Избегайте круговой ссылки:
Ответ Mitrenegades объясняет это, но если вашему проекту нужно использовать явный класс objc, который использует быстрый протокол (вместо использования протокола), тогда у вас будут проблемы с округлостью. Причина в том, что быстрый протокол определяется заголовком swift-objc, а затем вашим определением класса obj-c, который затем снова возвращается к заголовку swift-objc.
Решение Mitrenegades заключается в использовании протокола objective-c, это один из способов, но если вы хотите быстрый протокол, то другой будет реорганизовать код, чтобы не использовать класс objective-c напрямую, а вместо этого использовать протокол (например, шаблон на основе протокола factory). В любом случае это может быть подходящим для ваших целей.
Ответ 2
Если у вас
#import "moduleName-Swift.h"
в файле .h, который вы хотите быть делегатом, и у вас есть этот файл .h также в файле заголовков мостов, есть круговая ссылка, которая приводит к сбою компиляции moduleName-Swift.h. для проекта тестирования @james_alvarez, он, вероятно, работает, потому что вам не нужно включать TestObjClass.h в заголовок моста.
Лучший способ для меня объединить файлы objc, которые должны быть делегатом для класса, написанного в swift, но который также должен быть включен в заголовок моста, чтобы другие быстрые файлы могли получить доступ к этому классу objc, заключается в создании отдельный файл протокола в objc:
MyProtocol.h:
@protocol MyDelegate <NSObject>
-(void)didDoThis;
-(void)didDoThat;
@end
ViewController.h:
#import "MyProtocol.h"
@interface ViewController : UIViewController <MyDelegate>
MyProject-мост-header.h
#import "MyProtocol.h"
#import "ViewController.h"
Ответ 3
Я знаю, что это было давно, но я просто боролся с той же проблемой при добавлении протокола к моему Swift-коду, и он не добавлялся в заголовочный файл -Swift.h, следовательно, "Не удается найти протокол декларация"
Проблема заключалась в том, что мой протокол не был помечен как Public. Я изменил свой протокол:
@objc protocol MyProtocol { //etc.... }
:
@objc public protocol MyProtocol { //etc.... }
Я все еще не совсем уверен, зачем мне "публиковать", но никто больше не кажется, но он работает...
Ответ 4
Убедитесь, что вы включили автоматически созданный заголовок Swift в файл ObjectiveC. Он будет иметь то же имя, что и ваш модуль проекта, за которым следует -Swift.h
.
Например, если ваш модуль проекта MyTarget, вы должны использовать:
#import "MyTarget-Swift.h"
Если вы вводите импорт в свой файл Objective C, он не будет автозаполнен. Вы можете убедиться, что у вас есть правильный файл, нажав Command на заголовок после ввода его.
Ответ 5
Импортировать делегат как это в файле .h
@protocol AnalyticProtocol;
и добавьте это в файл .swift
@objc public protocol AnalyticProtocol {
}
Ответ 6
Попробуйте добавить #import "Product_Module_Name-Swift.h"
в ваш Product_Module_Name-Prefix.pch
файл. Это исправило это для меня, плюс теперь у вас будет доступ к вашим быстрым файлам из любого файла objc.