Нельзя использовать классы Swift внутри Objective-C

Я пытаюсь интегрировать код Swift в мое приложение. Мое приложение написано в Objective-C, и я добавил класс Swift. Я сделал все, что описано здесь. Но моя проблема заключается в том, что Xcode не создал файл -Swift.h, а только мосты. Поэтому я создал его, но он фактически пуст. Я могу использовать все классы ObjC в Swift, но я не могу это сделать наоборот. Я отметил мой быстрый класс @objc, но это не помогло. Что я могу сделать сейчас?

EDIT: Apple говорит: "Когда вы импортируете код Swift в Objective-C, вы полагаетесь на заголовочный файл Xcode-generated, чтобы выставить эти файлы в Objective-C. [...] Название этого заголовка - ваш продукт имя модуля, а затем добавление" -Swift.h".

Теперь, когда я хочу импортировать этот файл, он дает ошибку:

    //MainMenu.m

    #import "myProjectModule-Swift.h" //Error: 'myProjectModule-Swift.h' file not found

    @implementation MainMenu

Вот мой файл FBManager.swift:

@objc class FBManager: NSObject {

    var descr = "FBManager class"

    init() {
        super.init()
    }

    func desc(){
        println(descr)
    }

    func getSharedGameState() -> GameState{
        return GameState.sharedGameState() //OK! GameState is written in Objective-C and no error here
    }
}

Ответ 1

Я потратил около 4 часов, пытаясь включить Swift в моем проекте Xcode Objective-C. Мой файл myproject-Swift.h был успешно создан, но мой Xcode не увидел мой Swift-classes. Итак, я решил создать новый Xcode Objc-проект и, наконец, я нашел правильный ответ! Надеюсь, этот пост кому-нибудь поможет :-)

Пошаговая интеграция Swift для проекта на базе Xcode Objc:

  1. Создайте новый файл *.swift (в Xcode) или добавьте его с помощью Finder.
  2. Создайте Objective-C bridging header, когда Xcode спросит вас об этом.
  3. Реализуйте свой класс Swift:

    import Foundation
    
    // use @objc or @objcMembers annotation if necessary
    class Foo {
        //..
    }
    
  4. Откройте настройки сборки и проверьте следующие параметры:

    • Определяет модуль: YES

      Копировать и Вставить имя параметра в строку поиска

    • Название модуля продукта: myproject

      Убедитесь, что имя вашего модуля продукта не содержит специальных символов

    • Установите заголовок совместимости Objective-C: YES

      После добавления файла *.swift в проект это свойство появится в настройках сборки

    • Заголовок интерфейса, сгенерированный Objective-C: myproject-Swift.h

      Этот заголовок автоматически генерируется Xcode

    • Заголовок моста Objective-C: $(SRCROOT)/myproject-Bridging-Header.h
  5. Импортируйте заголовок интерфейса Swift в ваш файл *.m.

    #import "myproject-Swift.h"
    

    Не обращайте внимания на ошибки и предупреждения.

  6. Очистите и перестройте проект Xcode.
  7. Прибыль!

Ответ 2

Не создавайте файл заголовка самостоятельно. Удалите созданную вами.

Убедитесь, что ваши классы Swift отмечены @objc или наследуются от класса, который выводит (прямо или косвенно) из NSObject.

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

Ответ 3

Разрешить Xcode выполнять свою работу, не добавлять/создавать Swift-заголовок вручную. Просто добавьте @objc перед вашим классом Swift ex.

@objc class YourSwiftClassName: UIViewController

В вашем проекте выберите поиск ниже флагов и измените его на YES (Оба проекта и цели)

Defines Module : YES
Always Embed Swift Standard Libraries : YES
Install Objective-C Compatibility Header : YES

Затем очистите проект и создайте его один раз, после того, как сборка завершится успешно (возможно, она должна) импортировать ниже заголовочного файла в ваш .m файл objective-c.

#import "YourProjectName-Swift.h" 

Boooom!

Ответ 4

Также полезно для тех из вас, у кого есть Рамка-цель:

Оператор импорта автоматически сгенерированного файла заголовка выглядит как немного отличающийся от целей приложения. В дополнение к другим вещам, упомянутым в других ответах, используйте

#import <ProductName/ProductModuleName-Swift.h>

вместо

#import "ProductModuleName-Swift.h"

согласно документации на яблоки Mix и Match для целей инфраструктуры.

Ответ 5

Убедитесь, что ваш проект определяет модуль, и вы дали имя модулю. Затем перестройте, и Xcode создаст заголовочный файл -Swift.h, и вы сможете импортировать его.

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

Ответ 6

Детали: Objective-C проект с кодом Swift 3 в Xcode 8.1

Задачи:

  • Использовать swift перечисление в классе Objective-C
  • Использовать перечисление Objective-C в классе swift

ПОЛНЫЙ ОБРАЗЕЦ

1. Objective-C класс, который использует Swift enum

ObjcClass.h

#import <Foundation/Foundation.h>

typedef NS_ENUM(NSInteger, ObjcEnum) {
    ObjcEnumValue1,
    ObjcEnumValue2,
    ObjcEnumValue3
};

@interface ObjcClass : NSObject

+ (void) PrintEnumValues;

@end

ObjcClass.m

#import "ObjcClass.h"
#import "SwiftCode.h"

@implementation ObjcClass

+ (void) PrintEnumValues {
    [self PrintEnumValue:SwiftEnumValue1];
    [self PrintEnumValue:SwiftEnumValue2];
    [self PrintEnumValue:SwiftEnumValue3];
}

+ (void) PrintEnumValue:(SwiftEnum) value {
    switch (value) {
        case SwiftEnumValue1:
            NSLog(@"-- SwiftEnum: SwiftEnumValue1");
            break;

        case SwiftEnumValue2:
        case SwiftEnumValue3:
            NSLog(@"-- SwiftEnum: long value = %ld", (long)value);
            break;
    }
}

@end

Обнаружить код Swift в коде Objective-C

В моем примере я использую SwiftCode.h для обнаружения кода Swift в Objective-C. Этот файл генерируется автоматически (я не создал физическую копию этого заголовочного файла в проекте), и вы можете установить только имя этого файла:

введите описание изображения здесь

введите описание изображения здесь

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

2. Класс Swift, который использует Objective-C enum

import Foundation

@objc
enum SwiftEnum: Int {
    case Value1, Value2, Value3
}

@objc
class SwiftClass: NSObject {

    class func PrintEnumValues() {
        PrintEnumValue(.Value1)
        PrintEnumValue(.Value2)
        PrintEnumValue(.Value3)
    }

    class func PrintEnumValue(value: ObjcEnum) {
        switch value {
        case .Value1, .Value2:
            NSLog("-- ObjcEnum: int value = \(value.rawValue)")

        case .Value3:
            NSLog("-- ObjcEnum: Value3")
            break
        }

    }
}

Определить код Objective-C в коде Swift

Вам нужно создать файл заголовка моста. Когда вы добавляете файл Swift в проект Objective-C или файл Objective-C в быстрый проект Xcode предложит вам создать заголовок моста.

введите описание изображения здесь

Здесь вы можете изменить имя файла заголовка:

введите описание изображения здесь

Соединяя-header.h

#import "ObjcClass.h"

Использование

#import "SwiftCode.h"
...
[ObjcClass PrintEnumValues];
[SwiftClass PrintEnumValues];
[SwiftClass PrintEnumValue:ObjcEnumValue3];

Результат

введите здесь описание изображения


БОЛЬШЕ ОБРАЗЦОВ

Полные шаги интеграции Objective-C и Swift, описанные выше. Теперь я напишу несколько других примеров кода.

3. Вызов класса Swift из Objective-C кода

Класс Swift

import Foundation

@objc
class SwiftClass:NSObject {

    private var _stringValue: String
    var stringValue: String {
        get {
            print("SwiftClass get stringValue")
            return _stringValue
        }
        set {
            print("SwiftClass set stringValue = \(newValue)")
            _stringValue = newValue
        }
    }

    init (stringValue: String) {
        print("SwiftClass init(String)")
        _stringValue = stringValue
    }

    func printValue() {
        print("SwiftClass printValue()")
        print("stringValue = \(_stringValue)")
    }

}

Objective-C код (код вызова)

SwiftClass *obj = [[SwiftClass alloc] initWithStringValue: @"Hello World!"];
[obj printValue];
NSString * str = obj.stringValue;
obj.stringValue = @"HeLLo wOrLd!!!";

Результат

введите описание изображения здесь

4. Вызвать Objective-C класс из кода Swift

Objective-C class (ObjcClass.h)

#import <Foundation/Foundation.h>

@interface ObjcClass : NSObject
@property NSString* stringValue;
- (instancetype) initWithStringValue:(NSString*)stringValue;
- (void) printValue;
@end

ObjcClass.m

#import "ObjcClass.h"

@interface ObjcClass()

@property NSString* strValue;

@end

@implementation ObjcClass

- (instancetype) initWithStringValue:(NSString*)stringValue {
    NSLog(@"ObjcClass initWithStringValue");
    _strValue = stringValue;
    return self;
}

- (void) printValue {
    NSLog(@"ObjcClass printValue");
    NSLog(@"stringValue = %@", _strValue);
}

- (NSString*) stringValue {
    NSLog(@"ObjcClass get stringValue");
    return _strValue;
}

- (void) setStringValue:(NSString*)newValue {
    NSLog(@"ObjcClass set stringValue = %@", newValue);
    _strValue = newValue;
}

@end

Быстрый код (код вызова)

if let obj = ObjcClass(stringValue:  "Hello World!") {
    obj.printValue()
    let str = obj.stringValue;
    obj.stringValue = "HeLLo wOrLd!!!";
}

Результат

введите описание изображения здесь

5. Используйте расширение Swift в Objective-C code

Быстрое расширение

extension UIView {
    static func swiftExtensionFunc() {
        NSLog("UIView swiftExtensionFunc")
    }
}

Objective-C код (код вызова)

[UIView swiftExtensionFunc];

6. Используйте расширение Objective-C в быстром коде

Objective-C extension (UIViewExtension.h)

#import <UIKit/UIKit.h>

@interface UIView (ObjcAdditions)
+ (void)objcExtensionFunc;
@end

UIViewExtension.m

@implementation UIView (ObjcAdditions)
+ (void)objcExtensionFunc {
    NSLog(@"UIView objcExtensionFunc");
}
@end

Быстрый код (код вызова)

UIView.objcExtensionFunc()

Ответ 7

У меня была такая же проблема, и оказалось, что специальные символы в имени модуля заменяются на xcode (в моем случае тире оказались символом подчеркивания). В настройках проекта проверьте "имя модуля", чтобы найти имя модуля для вашего проекта. После этого либо используйте ModuleName-Swift.h, либо переименуйте модуль в настройках.

Ответ 8

Файл создается автоматически (здесь речь идет о Xcode 6.3.2). Но вы не увидите этого, так как он находится в папке Derived Data. После маркировки вашего быстрого класса @objc, скомпилируйте, затем найдите Swift.h в папке Derived Data. Здесь вы должны найти заголовок Swift.

У меня была проблема, что Xcode переименовал мой my-Project-Swift.h в my_Project-Swift.h Xcode не нравится "." "-" и т.д. символы. С помощью приведенного выше метода вы можете найти имя файла и импортировать его в класс Objective-C.

Ответ 9

Просто включите #import "myProject-Swift.h" в .m или .h файле

P.S Вы не найдете "myProject-Swift.h" в инспекторе файлов скрытым. Но он создается приложением автоматически.

Ответ 10

Существует два условия:

  • Используйте ваш быстрый файл в объектном файле c.
  • Используйте свой объектный файл c в быстром файле.

Итак, для этой цели вам необходимо выполнить следующие действия:

  • Добавьте ваш быстрый файл в проект objective-c или наоборот.
  • Создать файл заголовка (.h).
  • Перейдите в Настройки сборки и выполните следующие шаги при поиске,

    • найдите этот текст "brid" и установите путь к вашему файлу заголовка.
    • "Определяет модуль": ДА.
    • "Всегда вставлять быстрые стандартные библиотеки": ДА.
    • "Установить objective-c Заголовок совместимости": YES.

После этого очистите и перестройте свой проект.

Используйте ваш быстрый файл в объектном файле c.

В этом случае сначала напишите "@objc" перед вашим классом в swift файле.

После этого в своем объектном файле c напишите это,

  #import "YourProjectName-Swift.h"

Используйте свой объектный файл c в быстром файле.

В этом случае, в вашем файле заголовка, напишите это,

  #import "YourObjective-c_FileName.h"

Надеюсь, это поможет вам.

Ответ 11

@sig ответ один из лучших, однако он не работал у меня со старым проектом (не новым!), мне нужны были некоторые изменения. После многих вариаций я нашел рецепт для меня (используя XCode 7.2):

  • Имя модуля продукта: $(PRODUCT_NAME: c99extidentifier) ​​
  • Определяет модуль: NO
  • Встроенный контент содержит Swift: NO
  • Установить Objective-C Заголовок совместимости: YES
  • Objective-C Заголовок моста: ProjectName-Bridging-Header.h

Последняя точка (5) имела решающее значение. Я помещаю его только во второй раздел (поле "Цели" ), поле "Проект" должно быть пустым: enter image description here В противном случае он не создавал для меня файл "Project-Swift.h" (он не включал быстрые методы).

Ответ 12

В моем случае, помимо этих шагов:

  • Имя модуля продукта: myproject
  • Определяет модуль: ДА
  • Встроенный контент содержит Swift: YES
  • Установить Objective-C Заголовок совместимости: YES
  • Objective-C Заголовок моста: $(SRCROOT)/Sources/SwiftBridging.h

Мне нужно было поставить класс как public, чтобы создать файл productName-Swift.h:

import UIKit

   @objc public class TestSwift: NSObject {
       func sayHello() {
          print("Hi there!")
       }
   }

Ответ 13

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

Ответ 14

У меня была такая же проблема, и, наконец, оказалось, что они не привязаны к тем же целям. Класс ObjC привязан к Target1 и Target2, класс Swift привязан только к Target1 и не отображается внутри класса ObjC.

Надеюсь, это поможет кому-то.

Ответ 15

Моя проблема в том, что я застрял после того, как xcode создал файл моста, но все же я получил ошибку в имени файла заголовка MYPROJECTNAME-swift.h

1.I проверить терминал и искать все автоматически созданные файлы быстрого моста:

find ~/library/Developer/Xcode/DerivedData/ -name "*-Swift.h"|xargs basename|sort -

вы видите, какой xcode создан.

  1. В моем случае у меня было место в имени моего проекта, а вместо xcode это "_"

Ответ 16

Для Swift 5:

  1. Добавьте ключевое слово @objc в ваш класс и методы
  2. Добавьте public ключевое слово в ваш класс и методы
  3. Пусть ваш класс наследуется от NSObject
  4. Построить проект
  5. Поместите #import "MyProject-Swift.h" в ваш файл Objective-C

    @objc
    public class MyClass: NSObject {
    
        @objc
        public func myMethod() {
    
        }
    }
    

Ответ 17

Использование классов Swift в Objective-C

Если вы собираетесь импортировать код внутри цели приложения (смешивая Objective-C и Swift в одном проекте), вам следует использовать следующую строку импорта #import "<#YourProjectName#>-Swift.h", чтобы представить Swift-код в код Objective-C [Mixing Swift and Objective-C code in a project]

В этом посте я опишу, как импортировать статическую библиотеку Swift в код Objective-C

Потребитель Objective-C → Swift статическая библиотека

Версия Xcode 10.2.1

Создать статическую библиотеку Swift

Создать проект библиотеки или создать целевой объект библиотеки

File -> New -> Project... -> Cocoa Touch Static Library
//or
Project editor -> Add a Target -> Cocoa Touch Static Library 

Добавить файлы .swift

Select '.swift' file -> Select File Inspectors Tab -> Target Membership -> Select the target
//or
Project editor -> select a target -> Build Phases -> Compile Sources -> add files

Разоблачить Swift API. Использовать функции Swift из Objective-C[About]

Сборка библиотеки - ⌘ Command + B или Product -> Build

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

Найти сгенерированный вывод[Build location]

Products group -> lib<product_name>.a -> Show in Finder

Каталог включает в себя

  • lib<product_name>.a - встроенная статическая библиотека
  • Папка <product_name>.swiftmodule, которая включает в себя:
    • .swiftdoc - документы
    • .swiftmodule - общедоступный интерфейс/определения

Также вы должны найти файл <product_name>-Swift.h, который должен находиться в DerivedSources [File not found]

Использование статической библиотеки Swift

Drag and drop двоичный файл в проект Xcode[About]

Link Library[Undefined symbols] [Link vs Embed]

Project editor -> select a target -> General -> Linked Frameworks and Libraries -> add -> Add Others... -> point to 'lib<product_name>.a' file
//or
Project editor -> select a target -> Build Phases -> Link Binary With Libraries -> add -> Add Others... -> point to 'lib<product_name>.a' file

Добавить Library Search paths[Library not found for] [Recursive path]

Project editor -> select a target -> Build Settings -> Search Paths -> Library Search paths -> add path to the parent of 'lib<product_name>.a' file

Добавить Header Search Paths[Module not found] [Recursive path]

Project editor -> select a target -> Build Settings -> Search Paths -> Header Search Paths -> add path to generated '<product_name>-Swift.h' file 

Добавить пустой .swift file в проект Objective-C.[Undefined symbols] When Xcode ask press Create [TG420](it will create [TG421]) and setup a path to this file in

[TG16]

Import module to the Objective-C client code[File not found] [module_name]

[TG17]

More examples here

Ответ 18

У меня такая же ошибка: myProjectModule-Swift.h file not found ", но в моем случае реальная причина была в неправильной цели развертывания:" Swift недоступно в OS X раньше, чем 10.9, установите MACOSX_DEPLOYMENT_TARGET в 10.9 или новее (в настоящее время это "10.7" ) поэтому, когда я изменил цель развертывания на 10.9 - проект был скомпилирован успешно.

Ответ 19

Моя проблема заключалась в том, что автогенерация файла -swift.h не способна понять подкласс CustomDebugStringConvertible. Вместо этого я заменил класс на подкласс NSObject. После этого файл -swift.h теперь включил класс правильно.

Ответ 20

У меня были проблемы с тем, что я бы добавил классы в мой заголовок моста objective-c, а в этих objective-c заголовках, которые были импортированы, они пытались импортировать быстрый заголовок. Это не понравилось.

Итак, во всех моих классах objective-c, которые используют swift, но также мосты, ключ должен был убедиться, что вы используете объявления прямого класса в заголовках, а затем импортируете файл "* -Swift.h" в. m файл.

Ответ 21

Мне не нужно было менять какие-либо настройки в сборке или добавлять @obj в класс.

Все, что мне нужно было сделать, это создать bridge-header, который автоматически создавался при создании классов Swift в проекте Objective-c. И тогда я просто должен был сделать

import "Bedtime-Swift.h" <- внутри файла target-c, необходимого для использования этого файла swift.

Ответ 22

Ну, после прочтения всех комментариев, попыток, чтения и повторных попыток мне удалось включить быстрые классы в мой проект Big obj-c. Итак, спасибо за помощь. Я хотел поделиться одним советом, который помог мне лучше понять процесс. В классе .m, перейдите к строке импорта с именем целевого объекта swift #import "myTargetName-Swift.h" и нажмите клавишу:

команда + щелчок мыши → Перейти к определению enter image description here

Там вы можете увидеть все переводы от swift к obj-c, и вы найдете различные функции, повторно объявленные в obj-c. Надеюсь, этот совет поможет вам так же, как и мне.

Ответ 23

Когда вы добавляете новые файлы Swift в проект, пожалуйста, убедитесь, что вы добавляете их в правильные цели. Пожалуйста, убедитесь, что каждый файл swift, который вы собираетесь использовать, наследует класс NSObject и помечается как @ObjCMembers. Измените на YES в настройках сборки под опцией ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES. Измените на YES в настройках сборки под опцией DEFINES_MODULE.

Ответ 24

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

Я исправил это, выбрав [MyTarget]> "Фазы сборки"> "Копировать ресурсы комплекта", затем нажал кнопку "плюс" и добавил файлы Swift.