Я пытаюсь интегрировать код 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
}
}
Я потратил около 4 часов, пытаясь включить Swift
в моем проекте Xcode
Objective-C. Мой файл "myproject-Swift.h
" был успешно создан, но мой Xcode
не видел моего Swift-classes
. Итак, я решил создать новый проект Xcode
Objc, и, наконец, я нашел правильный ответ! Надеюсь, что этот пост поможет кому-то: -)
*.swift
файл (в Xcode) или добавьте его с помощью FinderObjective-C bridging header
, когда Xcode спросит вас об этомВнедрите свой класс Swift с атрибутом @objc
:
import UIKit
@objc public class CustomView: UIView {
override func draw(_ rect: CGRect) {
// Drawing code
}
}
Откройте "Настройки сборки" и проверьте эти параметры:
YES
myproject
Убедитесь, что ваше имя модуля продукта не содержит специальных символов
YES
После добавления в проект файла
*.swift
это свойство появится в настройках сборки
myproject-Swift.h
Этот заголовок автоматически генерируется Xcode
$(SRCROOT)/myproject-Bridging-Header.h
Импортировать заголовок интерфейса Swift в файл *.m
#import "myproject-Swift.h"
Не обращайте внимания на ошибки и предупреждения.
Не создавайте файл заголовка самостоятельно. Удалите созданную вами.
Убедитесь, что ваши классы Swift отмечены @objc
или наследуются от класса, который выводит (прямо или косвенно) из NSObject
.
Xcode не будет генерировать файл, если у вас есть какие-либо ошибки компилятора в вашем проекте - убедитесь, что ваш проект строит чисто.
find ~/library/Developer/Xcode/DerivedData/ -name "*-Swift.h"|xargs basename|sort -u
чтобы увидеть, был ли создан файл с неожиданным именем, например это было для меня. :)
Разрешить 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!
Также полезно для тех из вас, у кого есть Рамка-цель:
Оператор импорта автоматически сгенерированного файла заголовка выглядит как немного отличающийся от целей приложения. В дополнение к другим вещам, упомянутым в других ответах, используйте
#import <ProductName/ProductModuleName-Swift.h>
вместо
#import "ProductModuleName-Swift.h"
согласно документации на яблоки Mix и Match для целей инфраструктуры.
Убедитесь, что ваш проект определяет модуль, и вы дали имя модулю. Затем перестройте, и Xcode создаст заголовочный файл -Swift.h
, и вы сможете импортировать его.
Вы можете установить определение модуля и имя модуля в настройках проекта.
У меня была такая же проблема, и оказалось, что специальные символы в имени модуля заменяются на xcode (в моем случае тире оказались символом подчеркивания). В настройках проекта проверьте "имя модуля", чтобы найти имя модуля для вашего проекта. После этого либо используйте ModuleName-Swift.h
, либо переименуйте модуль в настройках.
Файл создается автоматически (здесь речь идет о Xcode 6.3.2). Но вы не увидите этого, так как он находится в папке Derived Data. После маркировки вашего быстрого класса @objc
, скомпилируйте, затем найдите Swift.h
в папке Derived Data. Здесь вы должны найти заголовок Swift.
У меня была проблема, что Xcode переименовал мой my-Project-Swift.h
в my_Project-Swift.h
Xcode не нравится
"." "-"
и т.д. символы. С помощью приведенного выше метода вы можете найти имя файла и импортировать его в класс Objective-C.
#import "my_project-Swift.h"
и мое фактическое имя проекта - my-project
Просто включите #import "myProject-Swift.h" в .m или .h файле
P.S Вы не найдете "myProject-Swift.h" в инспекторе файлов скрытым. Но он создается приложением автоматически.
Детали: Objective-C проект с кодом Swift 3 в Xcode 8.1
Задачи:
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
В моем примере я использую SwiftCode.h для обнаружения кода Swift в Objective-C. Этот файл генерируется автоматически (я не создал физическую копию этого заголовочного файла в проекте), и вы можете установить только имя этого файла:
Если компилятор не может найти файл заголовка Swift, попытайтесь скомпилировать проект.
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
}
}
}
Вам нужно создать файл заголовка моста. Когда вы добавляете файл Swift в проект Objective-C или файл Objective-C в быстрый проект Xcode предложит вам создать заголовок моста.
Здесь вы можете изменить имя файла заголовка:
Соединяя-header.h
#import "ObjcClass.h"
#import "SwiftCode.h"
...
[ObjcClass PrintEnumValues];
[SwiftClass PrintEnumValues];
[SwiftClass PrintEnumValue:ObjcEnumValue3];
Полные шаги интеграции Objective-C и Swift, описанные выше. Теперь я напишу несколько других примеров кода.
Класс 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!!!";
Результат
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!!!";
}
Результат
Быстрое расширение
extension UIView {
static func swiftExtensionFunc() {
NSLog("UIView swiftExtensionFunc")
}
}
Objective-C код (код вызова)
[UIView swiftExtensionFunc];
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()
Существует два условия:
Итак, для этой цели вам необходимо выполнить следующие действия:
Перейдите в Настройки сборки и выполните следующие шаги при поиске,
После этого очистите и перестройте свой проект.
В этом случае сначала напишите "@objc" перед вашим классом в swift файле.
После этого в своем объектном файле c напишите это,
#import "YourProjectName-Swift.h"
В этом случае, в вашем файле заголовка, напишите это,
#import "YourObjective-c_FileName.h"
Надеюсь, это поможет вам.
@sig ответ один из лучших, однако он не работал у меня со старым проектом (не новым!), мне нужны были некоторые изменения. После многих вариаций я нашел рецепт для меня (используя XCode 7.2):
Последняя точка (5) имела решающее значение. Я помещаю его только во второй раздел (поле "Цели" ), поле "Проект" должно быть пустым: В противном случае он не создавал для меня файл "Project-Swift.h" (он не включал быстрые методы).
В моем случае, помимо этих шагов:
Мне нужно было поставить класс как public, чтобы создать файл productName-Swift.h:
import UIKit
@objc public class TestSwift: NSObject {
func sayHello() {
print("Hi there!")
}
}
У меня была такая же проблема, и, наконец, оказалось, что они не привязаны к тем же целям. Класс ObjC привязан к Target1 и Target2, класс Swift привязан только к Target1 и не отображается внутри класса ObjC.
Надеюсь, это поможет кому-то.
Я только что обнаружил, что добавление каталога быстрых файлов в проект не будет работать. Сначала вам нужно создать группу для каталога, а затем добавить быстрые файлы...
У меня были проблемы с тем, что я бы добавил классы в мой заголовок моста objective-c, а в этих objective-c заголовках, которые были импортированы, они пытались импортировать быстрый заголовок. Это не понравилось.
Итак, во всех моих классах objective-c, которые используют swift, но также мосты, ключ должен был убедиться, что вы используете объявления прямого класса в заголовках, а затем импортируете файл "* -Swift.h" в. m файл.
Моя проблема в том, что я застрял после того, как xcode создал файл моста, но все же я получил ошибку в имени файла заголовка MYPROJECTNAME-swift.h
1.I проверить терминал и искать все автоматически созданные файлы быстрого моста:
find ~/library/Developer/Xcode/DerivedData/ -name "*-Swift.h"|xargs basename|sort -
вы видите, какой xcode создан.
Моя проблема заключалась в том, что автогенерация файла -swift.h не способна понять подкласс CustomDebugStringConvertible. Вместо этого я заменил класс на подкласс NSObject. После этого файл -swift.h теперь включил класс правильно.
У меня такая же ошибка: myProjectModule-Swift.h
file not found ", но в моем случае реальная причина была в неправильной цели развертывания:" Swift
недоступно в OS X раньше, чем 10.9, установите MACOSX_DEPLOYMENT_TARGET
в 10.9 или новее (в настоящее время это "10.7" )
поэтому, когда я изменил цель развертывания на 10.9 - проект был скомпилирован успешно.
YourProjectName-Swift.h
должен быть волшебным заголовочным файлом, который Xcode автоматически создает для вас во время компиляции (вы не увидите его в браузере проекта). Попробуйте удалить созданный вами#import YourProjectName-Swift.h
и добавьте#import YourProjectName-Swift.h
к файлам, в которых вы хотите использовать классы Swift.Swift
и как вы получаете к нему доступ изObjective-C
.