Objective-C中不能使用Swift类
我尝试将Swift
代码集成到我的应用程序中。我的应用程序是用Objective-C
编写的,我添加了一个Swift
类。 我已经做了一切描述在这里 。 但我的问题是, Xcode
还没有创建-Swift.h
文件,只有-Swift.h
。 所以我创建了它,但实际上是空的。 我可以在Swift中使用所有的ObjC类,但是我不能这样做。 我用@objc
标记了我的swift类,但是没有帮助。 我现在能做什么?
编辑:苹果说:“当你将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个小时,试图在基于Xcode
Objective-C的项目中启用Swift
。 我的“ myproject-Swift.h
”文件已经成功创建,但我的Xcode
没有看到我的Swift-classes
。 所以,我决定创建一个新的基于Xcode
Objc项目,最后我找到了正确的答案! 希望这个职位将有助于某人:-)
一步一步Swift集成Xcode基于Objc的项目:
- 创建新的
*.swift
文件(在Xcode中)或使用Finder添加它 - 当Xcode询问你时,创建一个
Objective-C bridging header
-
用
@objc
属性实现你的Swift类: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
- 定义模块:
-
在* .m文件中导入Swift接口标题
#import "myproject-Swift.h"
不要注意错误和警告。
- 清理并重建您的Xcode项目
- 利润!
不要自己创建头文件。 删除你创建的一个。
确保你的Swift类用@objc
标记,或者从NSObject
派生(直接或间接)的类继承。
如果您的项目中有任何编译器错误,Xcode将不会生成该文件 – 确保您的项目干净地构建。
允许Xcode执行它的工作,不要手动添加/创建Swift头。 只要在你的Swift类前添加@objc。
@objc class YourSwiftClassName: UIViewController
在你的项目设置中搜索下面的标志,并将其更改为YES(项目和目标)
Defines Module : YES Always Embed Swift Standard Libraries : YES Install Objective-C Compatibility Header : YES
然后清理项目并构建一次,构建成功后(可能应该)导入到您的objective-c类.m文件中的头文件下面
#import "YourProjectName-Swift.h"
Boooom!
也可能有助于你的框架目标的人 :
自动生成的头文件的导入语句与应用程序目标有点不同 。 除了在其他答案中提到的其他事情使用
#import <ProductName/ProductModuleName-Swift.h>
代替
#import "ProductModuleName-Swift.h"
根据苹果关于混合与匹配框架目标的文档。
确保你的项目定义了一个模块,并给出了模块的名称。 然后重建,Xcode将创建-Swift.h
头文件,您将能够导入。
您可以在项目设置中设置模块定义和模块名称。
我有同样的问题,事实证明,模块名称中的特殊符号被替换为Xcode(在我的情况下,破折号最后是下划线)。 在项目设置中,选中“模块名称”以查找项目的模块名称。 之后,使用ModuleName-Swift.h
或在设置中重命名模块。
该文件是自动创建的(在这里谈论Xcode 6.3.2)。 但是你不会看到它,因为它在Derived Data文件夹中。 使用@objc
标记swift类@objc
,编译,然后在Derived Data文件夹中搜索Swift.h
。 你应该在那里找到Swift标题。
我有这个问题,Xcode更名为my my-Project-Swift.h
my_Project-Swift.h
Xcode不喜欢"." "-"
"." "-"
等符号。 使用上面的方法,您可以找到文件名并将其导入到Objective-C类。
只需在.m或.h文件中包含#import“myProject-Swift.h”
PS你将不会在文件检查器中找到“myProject-Swift.h”它是隐藏的。 但它是由应用程序自动生成的。
详细信息:在Xcode 8.1中使用Swift 3代码的Objective-C项目
任务:
- 在Objective-C类中使用快速枚举
- 在swift类中使用objective-c enum
完整的示例
1.使用Swift枚举的Objective-C类
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
检测Objective-C代码中的Swift代码
在我的示例中,我使用SwiftCode.h来检测Objective-C中的Swift代码。 这个文件自动生成(我没有在一个项目中创建这个头文件的物理副本),你只能设置这个文件的名字:
如果编译器找不到你的头文件Swift代码,试着编译这个项目。
2.使用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项目中添加Swift文件或者在Swift项目中添加Objective-C文件时,Xcode会建议您创建桥接标头。
您可以在此更改桥接头文件名称:
转职Header.h
#import "ObjcClass.h"
用法
#import "SwiftCode.h" ... [ObjcClass PrintEnumValues]; [SwiftClass PrintEnumValues]; [SwiftClass PrintEnumValue:ObjcEnumValue3];
结果
更多样本
上面描述的完整集成步骤Objective-c和Swift 。 现在我将写一些其他的代码示例。
3.从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!!!";
结果
4.从Swift代码中调用Objective-c类
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
Swift代码(调用代码)
if let obj = ObjcClass(stringValue: "Hello World!") { obj.printValue() let str = obj.stringValue; obj.stringValue = "HeLLo wOrLd!!!"; }
结果
5.在Objective-c代码中使用Swift扩展
Swift扩展
extension UIView { static func swiftExtensionFunc() { NSLog("UIView swiftExtensionFunc") } }
Objective-C代码(调用代码)
[UIView swiftExtensionFunc];
6.在Swift代码中使用Objective-C扩展
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
Swift代码(调用代码)
UIView.objcExtensionFunc()
有两个条件,
- 在目标c文件中使用你的swift文件。
- 在swift文件中使用你的目标c文件。
所以,为了这个目的,你必须按照下面的步骤进行:
- 在一个Objective-C项目中添加你的swift文件,反之亦然。
- 创建标题(.h)文件。
-
转到构建设置并执行以下搜索步骤,
- 搜索这个文本“brid”并设置头文件的路径。
- “定义模块”:是。
- “总是嵌入Swift标准库”:是的。
- “安装Objective-C兼容性头”:是。
之后,清理并重建您的项目。
在目标c文件中使用你的swift文件。
在这种情况下,首先在swift文件中写上“@objc”。
之后,在你的目标c文件中,写下这个,
#import "YourProjectName-Swift.h"
在swift文件中使用你的目标c文件。
在这种情况下,在你的头文件中,写这个,
#import "YourObjective-c_FileName.h"
我希望这会帮助你。
@sig答案是最好的之一,但是,它不适合我的旧项目(不是新的!),我需要一些修改。 经过很多变化,我找到了我的食谱(使用XCode 7.2):
- 产品模块名称:$(PRODUCT_NAME:c99extidentifier)
- 定义模块:NO
- 嵌入式内容包含Swift:NO
- 安装Objective-C兼容性头文件:YES
- Objective-C桥接头:ProjectName-Bridging-Header.h
最后一点(5)是至关重要的。 我只把它放在第二部分(目标字段),项目字段应该留空: 否则,它不会为我生成正确的“Project-Swift.h”文件(它不包含swift方法)。
就我而言,除了这些步骤:
- 产品模块名称: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!") } }
我刚刚发现,添加一个swift文件目录到一个项目将无法正常工作。 您需要先为该目录创建一个组,然后添加swift文件…
我也遇到了同样的问题,最后看来他们并没有遵守同样的目标。 ObjC类附加到Target1和Target2,Swift类只附加到Target1,在ObjC类中不可见。
希望这有助于某人。
我有同样的错误: myProjectModule-Swift.h
文件“,但在我的情况下,真正的原因是错误的部署目标:” Swift
在10.9以前的OS X上不可用; 请将MACOSX_DEPLOYMENT_TARGET
设置为10.9或更高版本(当前为“ MACOSX_DEPLOYMENT_TARGET
”),因此,当我将部署目标更改为10.9时,项目已成功编译。
我的问题是,自动生成的-swift.h文件无法理解CustomDebugStringConvertible的子类。 我把类改为NSObject的一个子类。 在那之后,-swift.h文件现在包含了这个类。
我的问题是我被困在Xcode创建桥文件后,但仍然在头文件名称错误MYPROJECTNAME-swift.h
我检查终端并搜索所有自动创建的快速桥接文件:
find ~/library/Developer/Xcode/DerivedData/ -name "*-Swift.h"|xargs basename|sort -
你看看Xcode创建了什么。
- 在我的情况下,我有我的项目名称和Xcode空间替换这是'_'
我有问题,我会添加类到我的objective-c桥头,并在那些被导入的目标C头,他们试图导入swift头。 它不是那样的。
因此,在所有使用swift的Objective-C类中,也是桥接的,关键是确保在头文件中使用前向类声明,然后在.m文件中导入“* -Swift.h”文件。