Как предотвратить циклическую ссылку, когда соединительный заголовок Swift импортирует файл, который импортирует сам Hopscotch-Swift.h

Я интегрирую Swift в большой существующий проект Objective C и столкнулся с тем, что я считаю круговой ссылкой.

Рассматриваемые классы следующие:

Objective C Controller

#import "Hopscotch-Swift.h"

@interface MyController : UIViewController<MyProtocol>
   ...
@end

Свифт протокол

@objc protocol MyProtocol: NSObjectProtocol {
   ...
}

Соединительный заголовок

#import "MyController.h"

Этот код не компилируется, потому что Hopscotch-Swift.h файл не будет генерироваться.

Я думаю, что это связано с ошибкой циклической ссылки, поскольку я могу импортировать Hopscotch-Swift.h в заголовки цели c, которые не включены в Hopscotch-Bridging-Header.h и работает нормально.

Есть ли решение этой проблемы или я должен подать радар в Apple?

5 ответов

Форвардная декларация должна работать, в вашем случае.

В вашем.h:

@protocol MyProtocol;

@interface MyController : UIViewController<MyProtocol>

@end

В вашем.m:

#import "HopScotch-Swift.h"

Как я могу добавить прямые ссылки на классы, используемые в заголовке -Swift.h? и руководство по совместимости Swift:

Если вы используете свои собственные типы Objective C в своем коде Swift, обязательно импортируйте заголовки Objective C для этих типов, прежде чем импортировать сгенерированный заголовок Swift в файл Objective C, из которого вы хотите получить доступ к коду Swift.

Я столкнулся с этим, когда пытался использовать классы Swift внутри протоколов Objective-C, где протокол также был реализован другим классом Swift. В нем пахло циклическими ссылками, и я догадался, что это может быть попытка циклически сгенерировать связующие заголовки, а не "нормальная" проблема циклического включения.

Для меня решение было просто использовать предварительные объявления перед объявлением протокола:

// don't include the MyProject-Swift.h header

// forward declaration of Swift classes used
@class SwiftClass;

@protocol MyProtocol <NSObject>
- (SwiftClass *)swiftClass;
@end

Предварительная декларация сама по себе не сработала. Он скомпилирован без ошибок, но все еще имел предупреждения, что протокол не может быть найден. Я воспринимаю все предупреждения как ошибки, так что этого недостаточно.

Я смог это исправить, переместив реализацию протокола в заголовок другой категории.

Вот что сработало для меня:

В моем MyOtherSwiftFile.swift:

@objc protocol MyProtocol: class {
func viewController(didFinishEditing viewController: MyViewController)
}

В моем MyViewController.h:

@interface MyViewController // Removed protocol implementation declaration here
@end

Добавил MyViewController+MyProtocol.h в проект и поместил это там:

@interface MyViewController (MyProtocol) <MyProtocol>
@end

Сами методы могут оставаться там, где они есть, если хотите.

После того, как вы реализуете вышеизложенное и компилируете, вы получите предупреждение (и) компилятора где-то в вашем коде, который требует MyViewController инвентарь MyProtocol, В этом файле вы будете #import "MyViewController+MyProtocol.h"

В качестве альтернативы вы можете преобразовать свой протокол в протокол Objective-C, а затем использовать его в Swift, включивMyProtocol.hв вашем связующем заголовке.

Вы можете что-то вроде этого в файле.h, который вы подозреваете, вызвать циклическую ссылку:

#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif
Другие вопросы по тегам