Как получить доступ к внутреннему классу Swift в Objective-C в рамках одной и той же структуры?
Работа с смешанной структурой. импортированный внутри файла Obj-C, но внутренние классы не видны, только публичные.
В документации четко указано, что внутренние кланы должны быть доступны между Swift и Obj-C:
Импорт Swift в Objective-C
Чтобы импортировать набор файлов Swift в тот же целевой объект инфраструктуры, что и ваш Objective-C, вы не используете необходимо импортировать что-либо в заголовок зонтика для фреймворка. Вместо этого импортируйте заголовочный файл сгенерированный Xcode для вашего кода Swift в любой файл Objective-C.m, с которого вы хотите использовать код Swift. Поскольку сгенерированный заголовок для целевой среды является частью frameworks public interface, только декларации, помеченные общественностью модификатор появляется в сгенерированном заголовке для целевой среды. Вы все еще могут использовать методы и свойства Swift, отмеченные внутренний модификатор из Objective-C части вашей структуры, пока они объявлены в классе, который наследуется от Objective-C класс. Для получения дополнительной информации о модификаторах уровня доступа см. Контроль доступа в Быстрый язык программирования (Swift 2).
Пример кода (создайте новый проект с каркасом)
// SwiftObject.swift
public class SwiftObject: NSObject {
public class func doSomething() {}
}
internal class YetAnotherSwiftObject: NSObject {
internal class func doSomething() {}
}
// SomeObject.m file
@implementation SomeObject
- (void)someMethod {
[SwiftObject doSomething];
}
- (void)someOtherMethod {
[YetAnotherSwiftObject doSomething]; // Use of undeclared identifier
}
@end
Ответы
Ответ 1
Как указано в документах, объявления, помеченные модификатором internal
, не отображаются в сгенерированном заголовке, поэтому компилятор не знает о них и, следовательно, жалобах. Конечно, вы можете отправлять сообщения с использованием подхода performSelector
, но это не удобно и подвержено ошибкам. Нам просто нужно помочь компилятору узнать, что эти объявления есть.
Во-первых, нам нужно использовать вариант атрибута @objc
, который позволяет указать имя для вашего символа в Objective-C:
// SwiftObject.swift
@objc(SWIFTYetAnotherSwiftObject)
internal class YetAnotherSwiftObject: NSObject {
internal class func doSomething() {}
}
И тогда вам просто нужно создать объявление @interface
с помощью методов, которые вы хотите использовать в своем коде, - поэтому компилятор будет счастлив, а также примените макрос SWIFT_CLASS
с указанным ранее символом - так компоновщик выберет фактическую реализацию:
// SomeObject.m file
SWIFT_CLASS("SWIFTYetAnotherSwiftObject")
@interface YetAnotherSwiftObject : NSObject
+ (void)doSomething;
@end
@implementation SomeObject
- (void)someOtherMethod {
[YetAnotherSwiftObject doSomething]; // Should work now !!!
}
@end
- Я использовал декларацию интерфейса в формате .m только для ясности, лучшим вариантом было бы объединить такие объявления в файле .h и включить его.
- Объявляя методы в этом интерфейсе, мы обещаем компилятору, и он не будет жаловаться, если вы поместите туда метод, который не существует (или с неправильной подписью и т.д.). Очевидно, вы будете в этом случае сбой во время выполнения - так что будьте осторожны.
Ответ 2
Для меня это просто работало, проверяя: "Разрешить только API расширения приложения". Вы найдете его, перейдя к настройке проекта, выберите свою цель, а затем на вкладке "Общие" в разделе "Сведения о развертывании".
Может кто-нибудь объяснить мне, почему это решает проблему?