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

200

Я пытаюсь интегрировать код 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
    }
}
  • 25
    YourProjectName-Swift.h должен быть волшебным заголовочным файлом, который Xcode автоматически создает для вас во время компиляции (вы не увидите его в браузере проекта). Попробуйте удалить созданный вами #import YourProjectName-Swift.h и добавьте #import YourProjectName-Swift.h к файлам, в которых вы хотите использовать классы Swift.
  • 0
    Покажите определение вашего класса Swift и как вы получаете к нему доступ из Objective-C .
Показать ещё 7 комментариев
Теги:

18 ответов

420

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

Шаг за шагом Быстрая интеграция для проекта на основе кода Xcode Objc:

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

    import UIKit
    
    @objc public class CustomView: UIView {
        override func draw(_ rect: CGRect) {
            // Drawing code
        }
    }
    
  • Откройте "Настройки сборки" и проверьте эти параметры:

    • Определяет модуль: YES
    • Имя модуля продукта: myproject

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

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

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

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

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

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

    #import "myproject-Swift.h"
    

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

  • Очистите и перестройте проект Xcode
  • Profit!
  • 2
    Кто-нибудь видел упоминание о требуемой конфигурации (по крайней мере для меня) в документации по адресу: developer.apple.com/library/prerelease/ios/documentation/Swift/… в шаге 4 выше? Если это так, я пропустил это. Спасибо @ сиг.
  • 0
    В моем случае файл _swift.h даже не создается в моей папке DerivedSources. Конечно, я не могу регулярно компилировать, поскольку тот факт, что класс swift не найден, приводит к ошибкам. Должен ли я удалить классы swift и вызовы к ним, перестроить, а затем снова прочитать файл и вызовы?
Показать ещё 30 комментариев
52

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

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

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

  • 8
    быть способным к сборке было для меня ключом. Не удалось собрать, потому что не смог найти мой файл -swift.h, но не смог найти мой файл -swift.h, потому что не смог собрать: /
  • 12
    @anders, будучи пойманным в ловушку в этом цикле, вы можете использовать find ~/library/Developer/Xcode/DerivedData/ -name "*-Swift.h"|xargs basename|sort -u чтобы увидеть, был ли создан файл с неожиданным именем, например это было для меня. :)
Показать ещё 1 комментарий
29

Разрешить 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!

  • 1
    Это работает для меня!
  • 1
    Спасибо, это было фантастически просто и решило мою проблему.
Показать ещё 8 комментариев
21

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

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

#import <ProductName/ProductModuleName-Swift.h>

вместо

#import "ProductModuleName-Swift.h"

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

  • 3
    Вы понятия не имеете, что вы спасатель жизни. Бесконечно благодарен !!!
  • 1
    @dinesharjani Рад, что смог помочь! :)
Показать ещё 2 комментария
14

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

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

11

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

  • 10
    Я дебил. Я добавил имя класса, а затем добавил "-Swift". Оказывается, это название "модуля". +1 за то, что заставил меня понять это.
  • 2
    Еще один придурок, который думал, что это имя класса!
10

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

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

  • 0
    спасибо, это решило это для меня
  • 1
    Это тоже решило мою проблему. В моем .m файле я импортирую файл как этот #import "my_project-Swift.h" и мое фактическое имя проекта - my-project
Показать ещё 1 комментарий
8

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

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

  • 0
    Спасибо за внимание, приятель.
  • 0
    Этот ответ помог мне и спас мой день. Важно то, что Xcode генерирует его автоматически, и это скрытый файл. Я сам создавал «myProject-Swift.h», и он не работал.
7

Детали: 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. Этот файл генерируется автоматически (я не создал физическую копию этого заголовочного файла в проекте), и вы можете установить только имя этого файла:

Изображение 1753

Изображение 1754

Если компилятор не может найти файл заголовка 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 предложит вам создать заголовок моста.

Изображение 1755

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

Изображение 1756

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

#import "ObjcClass.h"

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

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

Результат

Изображение 1757


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

Полные шаги интеграции 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!!!";

Результат

Изображение 1758

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!!!";
}

Результат

Изображение 1759

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()
5

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

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

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

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

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

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

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

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

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

  #import "YourProjectName-Swift.h"

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

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

  #import "YourObjective-c_FileName.h"

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

4

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

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

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

  • 1
    также полезная ссылка: ericasadun.com/2014/08/21/…
  • 1
    Спасибо, спасибо, спасибо. Большое спасибо @DariusMiliauskas работает только с вашей ссылкой.
Показать ещё 3 комментария
3

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

  • Имя модуля продукта: 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!")
       }
   }
2

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

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

  • 0
    Я полностью упустил из виду это с разными целями для постановки и производства. Спасибо за ваш ответ!
2

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

  • 0
    @ <определенный класс>; должны быть определены, и тогда использующий проект увидит эти файлы.
0

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

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

0

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

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

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

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

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

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

0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню