Імпорт протоколу Swift в клас Objective-C


116

Я намагаюся імпортувати протокол Swift, названий AnalyticProtocolу клас з назвою Objective-C AnalyticFactory.

protocol AnalyticProtocol
{

}

Я починаю з існуючого проекту Objective-C (я не створив новий проект Swift за допомогою xCode і не знайшов, як налаштувати мій проект Objective-C на проект Swift в xCode 6 ).

У свій файл Swift я включив .hназваний файл, MyProjectName-Swift.hале компілятор повертає мені помилку про те, що він не існує . Отже, я створив .hфайл з ім'ям, MyProjectName-Swift.hякий насправді порожній (я не знаю, що мені слід помістити всередину).

У документації Apple , вони сказали , що я повинен включити свій .hфайл з ім'ям MyProjectName-Swift.hв моєму .mфайлі. Але мені потрібно включати його не у свій .mфайл, а у свій .h. Це може бути проблематично?

Коли я намагаюся компілювати, я отримав цю помилку:: 0: помилка: xxxAnalyticFactory.h: 39: не вдається знайти протокол декларації для "AnalyticProtocol"

І інкримінований код:

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

Я думаю, що я не дуже добре розумію, як можна імпортувати протокол Swift в клас Objective-C.

Хтось бачить помилку в тому, що я роблю?


Перегляньте інтеграційне відео Swift With Objective-C від WWDC 2014. Близько 30:40 у відео вони описують, як отримати доступ до протоколів Swift у класах Objective-C.
Джеймі Форест

Відповіді:


224

Вам потрібно додати @objcатрибут до протоколу Swift так:

@objc protocol AnalyticProtocol {

}

25
Дякую за вашу відповідь, але проблема все ще зберігається.
Жан Лебрумент

Чи можете ви опублікувати зразок проекту, який відтворює проблему?
Джеймі Форест

Додавання @objc допомогло мені імпортувати класи Swift до Obj-C
serg

19
@objc не завжди працює. При узгодженні з протоколом іноді це не працює, додаючи протокол @interfaceу .hфайл. проте, ви можете додати протокол до приватного @interfaceу .mфайлі, і він виправляє речі (принаймні, це є для мене при нагоді). Так вище ваш @implementationє @interface MyController() <AnalyticProtocol>.
Адам

1
Іноді Xcode 8 скаржиться під час редагування, але коли ви насправді будуєте його, дотримуючись цієї відповіді разом із коментарями, помилка піде.
Роджер Пінглтон

77

Не можна імпортувати заголовок Swift, створений Xcode, у файли заголовків objC.

Отже, оскільки ви хочете використовувати код Swift у файлі заголовка objC, вам потрібно буде "переслати декларувати" класи та протоколи, які ви хочете використовувати у файлі заголовка objC, як це:

@protocol AnalyticProtocol;

Тепер ви можете використовувати протокол у декларації про клас objC:

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

У ваш файл реалізації (файл objC .m) ви можете імпортувати заголовок Swift, створений Xcode ("ProductModuleName-Swift.h"), і правильна реалізація AnalyticProtocolтепер буде відома компілятору.

Це також описано в розділі "Використання Swift від Objective-C" в Документах Apple

Зауважте, що XCode видасть попередження у файлі заголовка objC, коли ви використовуєте протокол, оголошений вперед ("Не вдалося знайти визначення протоколу для" AnalyticProtocol "), але це можна ігнорувати - реалізація знайдеться під час компіляції.


19
Чому Xcode показує попередження про відсутній протокол, коли він компілюється та працює добре? Будь-який спосіб зняти попередження?
Орен

Досі неможливо викликати методи протоколу цього класу. Це дасть помилкуNo visible @interface for <ClassName> declares the selector <protocolMethodName>
Ельза

воно видає таке попередження: "Не вдалося знайти визначення протоколу для xxxx"
JAHelia

51

Для всіх, хто просто повинен прийняти протокол - це можна зробити в два етапи, не створюючи жодних попереджень або помилок:

  1. У своєму .swiftфайлі додайте @objcперед назвою протоколу:

    @objc protocol AnalyticProtocol {
    
    }
  2. У свій .mфайл імпортуйте згенерований заголовок Swift та прийняти протокол у приватну категорію. (Файл заголовка називається автоматично):

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

Це рекомендований підхід від Apple. Дізнатися більше про змішування та суміщення Objective-C та Swift можна тут: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html


1
Я все одно отримую попередження, з попередньою заявою чи без. Я використовую протокол у розширенні.
Крісті Балуша

Неможливо імпортувати #import "AnalyticProtocol-Swift.h". Схоже, що WickerProtocol-Swift.h не генерується автоматично, як ви вже говорили.
Hlung

2
Це працювало для мене; ніякі інші пропозиції чи відповіді на цій сторінці не працювали. Я на Swift 4.
Poulsbo

1
Це було єдиним способом видалити попередження (хоча воно працює, коли протоколи знаходяться у файлі заголовка)
David P

1
Це ж посилання доступне через WebArchive: web.archive.org/web/20170310053717/https://developer.apple.com/…
Річард Топчій

3

Якщо ви створюєте рамки, необхідний імпорт

#import "ProductModuleName-Swift.h"

зміни до:

#import <ProductModuleName/ProductModuleName-Swift.h>

В цьому випадку ви також повинні зробити протокол швидкі громадськості :

@objc public protocol AnalyticProtocol {
  func something();
}

3

Ми можемо використовувати швидкі протоколи в Objective C з кількома змінами коду. Також оголошені протоколи @objc дозволяють мати необов'язкові та потрібні методи без реалізації за замовчуванням. Він має плюси і мінуси.

Насправді ми могли б перейменувати ім’я протоколу в більш описовий при використанні в «Цілі C.» Я використовую «@objc (alias_name)».

Ось код. Давайте будемо мати швидкий протокол з атрибутом @objc та псевдонімом, який потрібно використовувати в коді ObjC.

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

Тепер давайте дальше слово оголосити наш протокол у .h-файлі

@protocol ObjTableViewReloadable;

Тепер ви можете відповідати цьому протоколу у файлі .m та додати необхідні методи реалізації.

#import "MyApp-Swift.h"
@interface MyObjcViewController () <ObjTableViewReloadable>

Дякуємо, що опублікували це. Я дивлюся на застарілий код, старіший від бруду, і якщо такий підхід працює, це врятує мені тону болю. :)
Адріан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.