Заголовок Swift для Objective-C не содержит классов Swift

Я пытаюсь использовать классы Swift в моем коде Objective-C, однако мои классы Swift, похоже, не появляются в сгенерированном заголовке. В результате моя сборка завершилась неудачей с "Использование необъявленного идентификатора" HelloWorld ".

Я использовал шаблоны для создания проекта TestApp.

У меня есть следующие настройки сборки в моей цели:

  • Название продукта: TestApp
  • Имя модуля продукта: TestAppModule
  • Определяет модуль: Да

Документация Apple говорит, что используется #import <TestApp/TestAppModule-Swift.h>, но это не работает.

Вместо этого я использую #import "TestAppModule-Swift.h" в своем ".m" файле. Кажется, это находит.

Я могу перейти к нему, и он выглядит так...

// Generated by Swift version 1.0 (swift-600.0.34.4.5)

#if defined(__has_include) && __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#endif

...etc...

но не определены классы там.

У меня есть файл Swift в проекте, который выглядит так...

class HelloWorld {    
    func hello() {
        println("hello world")
    }
}

Почему это не работает, используя стандартное расположение файла заголовка #import <TestApp/TestAppModule-Swift.h>?

Как я могу получить мои быстрые классы в этом заголовочном файле, поэтому я не получу ошибку "необъявленный идентификатор"?

Ответ 1

Вот как я получил работу. Вы можете увидеть более крупный ответ здесь.

Измените это:

class HelloWorld {    
    func hello() {
        println("hello world")
    }
}

To:

@objc class HelloWorld { 

    class func newInstance() -> HelloWorld {
        return HelloWorld()
    }

    func hello() {
        println("hello world")
    }
}

Затем в вашем файле ObjC:

#import "TestApp-Swift.h"

И вызывается вот так:

HelloWorld * helloWorld = [HelloWorld newInstance];
[helloWorld hello];

Ответ 2

tl; dr Убедитесь, что у вас есть мостовой заголовок, если вы выполняете перекрестный вызов любой между Objective-C и Swift.

У меня была такая же проблема: я видел файл -Swift.h в DerivedData, но не упоминал о моих классах Swift. Я правильно импортировал файл заголовка, параметр "Определить модуль" был "ДА", а имя модуля продукта было правильным. Я попытался удалить и повторно добавить файлы Swift, очистить buiild, выйти из XCode и т.д., Не повезло.

Тогда я понял, что у меня не было файла -Bridging-Header.h в моем проекте, по-видимому, из-за того, как я вытащил его из предыдущего проекта. Не должно быть проблем, потому что я еще не звонил Objective-C из Swift. Но когда я добавил заголовок моста и ссылался на его путь в настройках сборки (Swift Compiler - Code Generation → Objective-C Bridging Header), это волшебным образом устранило проблему - в моем файле -Swift.h был внезапно заполнен SWIFT_CLASS ( ) доброта!

Итак, я предполагаю, что заголовок моста является фундаментальным для процесса, даже если вы НЕ используете Objective-C из Swift.


ОБНОВЛЕНИЕ: Я, наконец, понимаю это. Он связан с модификаторами public/internal access. Не уверен, что я пропустил это изначально, или если это дополнение к документам Apple, но теперь он четко заявляет: -

По умолчанию сгенерированный заголовок содержит интерфейсы для Swift объявления, отмеченные общедоступным модификатором. Он также содержит те помечены внутренним модификатором, если ваша целевая программа приложения имеет Objective-C заголовок заголовка.

Ответ 3

Собственно использовать #import "TestAppModule-Swift.h" в ваших .m файлах. Если вам нужно ссылаться на класс в .h, используйте декларацию @class forward.

Кроме того, если вы хотите использовать класс Swift из Objective-C, класс Swift должен быть помечен атрибутом @objc. Xcode будет включать только классы с атрибутами, сгенерированными в сгенерированном заголовке. См. Также эту документацию.

Ответ 4

Класс должен быть объявлен как @objc общедоступный класс

Ответ 5

Более удобным способом было бы унаследовать NSObject. Например:

class HelloWorld: NSObject {    
    func hello() {
        println("hello world")
    }
}

Ответ 6

В моем случае класс не скомпилировался, потому что я сначала добавил его только к моей тестовой цели... После добавления его в мою главную цель (Build Phases → Compile Sources), он был скомпилирован и добавлен в файл заголовка.

Так много для TDD; -)

Ответ 7

В моем случае, следуя рекомендациям Apple, это не сработало, пока я не запустил проект. Редактор xcode продолжал отмечать неизвестный класс swift, пока я не щелкнул "run". Сборка прошла успешно, и быстрый метод работал.