it-swarm.com.ru

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

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

Правка: 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
    }
}
233
D Nagy

Я потратил около 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. Прибыль!
484
sig

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

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

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

61
Bill

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

@objc class YourSwiftClassName: UIViewController

В настройках вашего проекта найдите ниже флажки и измените его на ДА (как проект, так и цель)

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

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

#import "YourProjectName-Swift.h" 

Boooom!

33
Bharat Modi

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

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

#import <ProductName/ProductModuleName-Swift.h>

вместо

#import "ProductModuleName-Swift.h"

согласно документации Apple на Mix & Match для целевых структур.

27
Dschee

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

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

14
Leo Natan

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

11
Max Mikheyenko

Подробности: Проект Objective-C с кодом Swift 3 в Xcode 8.1

Задачи:

  1. Используйте перечисление Swift в классе Objective-C
  2. Используйте enum target-c в классе Swift 

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

1. Класс Objective-C, использующий перечисление Swift

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

 enter image description here

 enter image description here

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

2. Класс Swift, использующий перечисление Objective-C

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

 enter image description here

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

 enter image description here

Bridging-header.h

#import "ObjcClass.h"

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

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

Результат

 enter image description here


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

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

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

Свифт класс

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

Результат

 enter image description here

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

Класс Objective-C (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!!!";
}

Результат

 enter image description here

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

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

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

Код Objective-C (вызывающий код)

[UIView swiftExtensionFunc];

6. Используйте расширение Objective-c в коде Swift

Расширение Objective-C (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()
11
Vasily Bodnarchuk

Файл создается автоматически (о Xcode 6.3.2 здесь). Но вы не увидите его, так как он находится в папке «Производные данные». Отметив класс Swift с помощью @objc, скомпилируйте, а затем найдите Swift.h в папке производных данных. Вы должны найти заголовок Swift там.

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

9
brainray

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

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

8
Svitlana

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

  1. Имя модуля продукта: $ (PRODUCT_NAME: c99extidentifier) 
  2. Определяет модуль: НЕТ
  3. Встроенный контент содержит Swift: НЕТ
  4. Установить заголовок совместимости Objective-C: ДА
  5. Заголовок моста Objective-C: ProjectName-Bridging-Header.h

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

4
Darius Miliauskas

Есть два условия,

  • Используйте свой файл Swift в файле Objective C.
  • Используйте ваш файл Objective C в файле Swift.

Итак, для этого вы должны выполнить следующие шаги:

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

    1. найдите этот текст "brid" и укажите путь к вашему заголовочному файлу.
    2. «Определяет модуль»: ДА. 
    3. «Всегда встраивать Swift Стандартные библиотеки»: ДА. 
    4. «Установить заголовок совместимости Objective-C»: ДА.

После этого очистите и восстановите ваш проект.

Используйте свой файл Swift в файле Objective C.

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

После этого, в вашем файле Objective C, напишите это,

  #import "YourProjectName-Swift.h"

Используйте ваш файл Objective C в файле Swift.

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

  #import "YourObjective-c_FileName.h"

Я надеюсь, что это поможет вам.

4
vikas prajapati

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

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

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

import UIKit

   @objc public class TestSwift: NSObject {
       func sayHello() {
          print("Hi there!")
       }
   }
3
Saúl Moreno Abril

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

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

2
Dani.Rangelov

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

2
Darren Ehlers

Для 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() {
    
        }
    }
    
0
Nico S.

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

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

0
horseshoe7

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

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

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

0
coolcool1994

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

1. Я проверяю в терминале и ищу все автоматически созданные файлы моста Swift:

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

вы видите, что создал XCode.

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

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

0
Justin Domnitz

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

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

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

0
Techno Mag

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

0
slavik