无法在Objective-C中使用Swift类


260

我尝试将Swift代码集成到我的应用程序中,编写了我的应用程序Objective-C并添加了一个Swift类。我已经做了这里描述的一切。但是我的问题是Xcode还没有创建-Swift.h文件,只有桥接头文件。所以我创建了它,但是实际上它是空的。我可以在Swift中使用所有的ObjC类,但反之亦然。我用标记了我的快速班级,@objc但没有帮助。我现在能做什么?

编辑:苹果说:“当您将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
    }
}

27
YourProjectName-Swift.h应该是Xcode在编译过程中自动为您创建的一个神奇的头文件(您实际上不会在项目浏览器中看到它)。尝试删除您创建的类,然后将其添加#import YourProjectName-Swift.h到要使用Swift类的文件中。
格雷格

3
您正在构建的应用程序名为myProjectModule吗?该-Swift.h文件应以您的应用名称开头。您是否有以结尾的文件-Bridging-Header.h?你应该。如果是这样,该文件的第一部分就是您的项目名称。将文件名的第一部分与结合在一起-Swift.h,这就是您应该包括的内容。
vacawama 2014年

4
我已经在项目中成功运行了此程序,但是-Swift.h在Mac上找不到任何实际的文件结尾,但是我可以包含它。因此,不要挂断寻找这样的文件。只要确保您正确命名即可。
vacawama 2014年

2
@vacawama请注意,在将导入语句添加到Objective-C文件中之后,可以通过Command-Click导入来查看内容,就像访问任何其他头文件一样。
Kendall Helmstetter Gelner 2014年

4
我不得不使用#import <MyProjectName/MyProjectName-Swift.h>
Oliver Pearmain '16

Answers:


516

我花了大约4个小时尝试SwiftXcode基于Objective-C的项目中启用该功能。我的myproject-Swift.h文件创建成功,但是Xcode看不到Swift-classes。因此,我决定创建一个新Xcode的基于Objc的项目,最后,我找到了正确的答案!希望这篇文章能对某人有所帮助:-)

对于基于Xcode Objc的项目,逐步进行Swift集成:

  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. 在* .m文件中导入Swift接口头。

    #import "myproject-Swift.h"

    不要注意错误和警告。

  6. 清理并重建您的Xcode项目。
  7. 利润!

2
在上面的第4步中,有没有人看到文档(至少对我而言)在developer.apple.com/library/prerelease/ios/documentation/Swift/…中提到了所需的配置 ?如果是我错过了。谢谢@sig。
Morkrom 2014年

2
我的问题要简单得多-我找不到文件,"myproject-Swift.h"因此在我看来它似乎无法正常工作。显然,该文件在项目导航器中不可见。
2015年

6
@Asaf实际上,是的,此文件是由Xcode自动生成的,并位于您的项目构建路径中。因此,您可以在Finder /控制台中手动找到此文件,或者使用Cmd + LeftClick on在Xcode中直接打开它#import "myproject-Swift.h"
sig 2015年

1
对于我来说#5足以解决问题!
skywinder

12
使用您的这4个小时,您节省了我们的100个小时,非常感谢:)保存在我的最爱中;)
Abo3atef

65

不要自己创建头文件。删除您创建的一个。

确保您的Swift类被@objc(直接或间接)派生​​自的类标记或继承NSObject

如果您的项目中有任何编译器错误,Xcode均不会生成该文件-请确保您的项目构建干净。


8
对我而言,可构建是关键。无法建立,因为找不到我的-swift.h文件,但是却找不到我的-swift.h文件,因为它无法建立:/
anders

13
@anders被困在那个周期中时,您可以find ~/library/Developer/Xcode/DerivedData/ -name "*-Swift.h"|xargs basename|sort -u用来查看该文件是否使用像我这样的意外名称创建。:)
CodeReaper

38

允许Xcode完成其工作,请勿手动添加/创建Swift标头。只需在Swift类ex之前添加@objc。

@objc class YourSwiftClassName: UIViewController

在您的项目设置中搜索以下标志并将其更改为YES(Project和Target)

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

然后清理项目并构建一次,构建成功后(可能应该)在Objective-C类.m文件的头文件下导入

#import "YourProjectName-Swift.h" 


1
谢谢,这非常简单,可以解决我的问题。
费利佩

我在构建设置(Xcode 7.3.1)中看不到这些选项。我该怎么办?
iosdude

1
^不得不从顶部栏中的切换BasicAll
iosdude

1
Embedded Content Contains Swift改为Always Embed Swift Standard Libraries:在Xcode 8 stackoverflow.com/questions/38792650/...
威廉·大

@WilliamGrand感谢您的建议,更新了答案。
巴拉特·莫迪

28

对于那些拥有框架目标的人可能也有帮助:

自动生成的头文件的import语句看起来与应用程序目标有些不同。除了其他答案中提到的其他事项外,请使用

#import <ProductName/ProductModuleName-Swift.h>

代替

#import "ProductModuleName-Swift.h"

根据Apple关于Mix&Match框架目标的文档。


1
@dinesharjani很高兴我可以提供帮助!:)
Jeehut

捆绑包目标呢?
Iulian Onofrei,

14

确保您的项目定义了一个模块,并且为模块指定了名称。然后重建,Xcode将创建-Swift.h头文件,您将能够导入。

您可以在项目设置中设置模块定义和模块名称。


14

详细信息: Xcode 8.1中带有Swift 3代码的Objective-C项目

任务:

  1. 在Objective-C类中使用Swift枚举
  2. 在Swift类中使用Objective-C枚举

完整样本

1.使用Swift枚举的Objective-C类

对象类

#import <Foundation/Foundation.h>

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

@interface ObjcClass : NSObject

+ (void) PrintEnumValues;

@end

对象类

#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会建议您创建桥接标头。

在此处输入图片说明

您可以在此处更改桥接头文件名:

在此处输入图片说明

桥接头

#import "ObjcClass.h"

用法

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

结果

在此处输入图片说明


更多样品

上面描述的完全集成步骤Objective-c和Swift。现在,我将编写其他一些代码示例。

3.从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.从Swift代码调用Objective-c类

Objective-C类(ObjcClass.h)

#import <Foundation/Foundation.h>

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

对象类

#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扩展

迅捷扩展

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

Objective-C代码(调用代码)

[UIView swiftExtensionFunc];

6.在快速代码中使用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()

这些样本确实有帮助,谢谢!至于Swift 4+,我们需要@objcMembers在课程前面添加。因为@objc出于优化目的,在Swift 4中减少了推理。例如,默认情况下,NSObject派生类中的属性将不再推断@objc(就像在Swift 3中一样)。我从这个答案中得到了情报。
Hustlion

11

我遇到了同样的问题,结果模块名称中的特殊符号被xcode替换(在我的情况下,短划线最终变成了下划线)。在项目设置中,检查“模块名称”以找到您的项目的模块名称。之后,使用ModuleName-Swift.h或在设置中重命名模块。


10
我是白痴。我添加了类名,然后附加了“ -Swift”。原来是“模块”名称。+1使我意识到了这一点。
HotFudgeSunday

2
这里的另一个白痴谁以为是班名!
查理·马丁

9

该文件是自动创建的(在此谈论Xcode 6.3.2)。但是您看不到它,因为它位于“派生数据”文件夹中。在用标记了swift类之后@objc,进行编译,然后Swift.h在Derived Data文件夹中搜索。您应该在那里找到Swift标头。

我遇到了问题,即Xcode重命名my-Project-Swift.hmy_Project-Swift.hXcode时不喜欢 "." "-"等符号。使用上面的方法,您可以找到文件名并将其导入到Objective-C类。


1
这也解决了我的问题。在我的.m文件中,我这样导入文件,#import "my_project-Swift.h" 而我的实际项目名称为my-project
Bhavin_m 2015年

注意-不只是“。” “-”也空格:(
user1105951 '16

8

只需在.m或.h文件中包含#import“ myProject-Swift.h”

PS您不会在隐藏的文件检查器中找到“ myProject-Swift.h”。但是它是由应用自动生成的。


谢谢大家的注意,伙伴。
Felipe

这个答案帮助了我,挽救了我的一天。重要的是,Xcode会自动生成它,并且它是HIDDEN文件。我自己创建了“ myProject-Swift.h”,但无法正常工作。
C0mrade

5

@sig答案是最好的之一,但是,对于旧项目(不是新项目),它对我不起作用,我需要进行一些修改。经过很多变化后,我找到了适合我的食谱(使用XCode 7.2):

  1. 产品模块名称:$(PRODUCT_NAME:c99extidentifier)
  2. 定义模块:否
  3. 嵌入式内容包含Swift:否
  4. 安装Objective-C兼容性标头:是
  5. Objective-C桥接头:ProjectName-Bridging-Header.h

最后一点(5)至关重要。我仅将其放在第二部分(“目标”字段)上,“项目”字段应保留为空:在此处输入图片说明否则,它不会为我生成正确的“ Project-Swift.h”文件(它不包含swift方法)。


1
还有一个有用的链接:ericasadun.com/2014/08/21/...
大流士Miliauskas

1
谢谢,谢谢,谢谢,谢谢@DariusMiliauskas只让它与您的链接一起工作
a4arpan '16

1
@DariusMiliauskas非常感谢!这5点也为我在旧的Xcode项目中解决了问题
tatiana_c

Define Modules应该是No??
Sunil Chauhan

@SunilChauhan,是的,它仅用于framewoks
Iulian Onofrei

5

有两个条件

  • 在目标c文件中使用您的swift文件。
  • 在swift文件中使用目标c文件。

因此,为此,您必须执行以下步骤:

  • 将您的swift文件添加到Objective-C项目中,反之亦然。
  • 创建标头(.h)文件。
  • 转到“ 构建设置”,然后执行以下搜索步骤,

    1. 搜索此文本“ brid”并设置头文件的路径。
    2. “定义模块”:是。
    3. “始终嵌入Swift标准库”:是。
    4. “安装Objective-C兼容性标题”:是。

之后,清理并重建您的项目。

在目标c文件中使用您的swift文件。

在这种情况下,请先在您的班级之前的快速文件中写入“ @objc”。

之后,在您的目标c文件中,编写此代码,

  #import "YourProjectName-Swift.h"

在swift文件中使用目标c文件。

在这种情况下,请在您的头文件中编写此代码,

  #import "YourObjective-c_FileName.h"

我希望这能帮到您。


4

对于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() {
    
        }
    }

“将@objc关键字添加到您的类和方法中” –与Swift 4相同
Krzysztof Skrzynecki

3

就我而言,除了这些步骤:

  1. 产品模块名称:myproject
  2. 定义模块:是
  3. 嵌入式内容包含Swift:是
  4. 安装Objective-C兼容性标头:是
  5. Objective-C桥接标头:$(SRCROOT)/Sources/SwiftBridging.h

我需要将该类设置为公共,以便创建productName-Swift.h文件:

import UIKit

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

2

我只是发现将swift文件目录添加到项目中是行不通的。您需要先为目录创建一个组,然后添加快速文件...


@ <特定类别>; 应该定义,然后使用项目将看到那些文件。
Nikita

2

我遇到了同样的问题,最后看来他们并没有隶属于相同的目标。ObjC类附加到Target1和Target2,Swift类仅附加到Target1,在ObjC类内部不可见。

希望这对某人有帮助。


我完全忽略了这一点,因为它具有不同的登台和生产目标。谢谢您的回答!
本杰明·马丁

“附加”是什么意思?
Iulian Onofrei,

“ attached” =“ members”,他们应该被列为目标成员
Dani.Rangelov

1

我的问题是在xcode创建桥接文件后我被卡住了,但是头文件名MYPROJECTNAME-swift.h仍然出现错误

1.我签入终端并搜索所有自动创建的快速桥文件:

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

您会看到创建了什么xcode。

  1. 就我而言,我的项目名称中有空格,xcode替换为“ _”

1

将新的Swift文件添加到项目时,请确保将其添加到正确的目标。请确保要使用的每个swift文件都继承NSObject类,并使用@ObjCMembers注释。在选项ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES下的构建设置中将其更改为YES。在选项DEFINES_MODULE下的构建设置内更改为YES。


0

我有同样的错误:myProjectModule-Swift.h“找不到文件”,但就我而言,真正的原因是部署目标错误:“ Swift在OS X 10.9之前的版本中不可用;” 请设置MACOSX_DEPLOYMENT_TARGET为10.9或更高版本(当前为“ 10.7”)”,因此,当我将部署目标更改为10.9时-项目已成功编译。



0

我遇到的问题是,我要将类添加到我的Objective-C桥接标头中,并且在导入的那些Objective-C标头中,他们试图导入swift标头。不喜欢那样

因此,在所有使用swift但也进行了桥接的Objective-c类中,关键是要确保您在标头中使用前向类声明,然后在.m文件中导入“ * -Swift.h”文件。


0

我不必更改构建中的任何设置或将@obj添加到类中。

我要做的就是创建桥头,当我在Objective-c项目中创建Swift类时会自动创建桥头。然后我只需要做

在需要使用该swift文件的objective-c文件中导入“ -Bedtime-Swift.h” <-。


0

好了,在阅读完所有注释并尝试阅读并再次尝试之后,我设法将快速类包含到我的Big obj-c项目中。因此,感谢您的所有帮助。我想分享一个技巧,以帮助我更好地理解该过程。在.m类中,转到快速目标名称#import“ myTargetName-Swift.h”的导入行,然后单击以下键:

命令+鼠标单击->跳转到定义 在此处输入图片说明

在那里,您可以看到从swift到obj-c的所有转换,然后您会发现obj-c中重新声明的各种功能。希望本技巧对您有所帮助。


0

在Objective-C中使用Swift类

如果要在应用程序目标中导入代码(在一个项目中混合Objective-C和Swift),则应使用下一个导入行将#import "<#YourProjectName#>-Swift.h"Swift代码公开给Objective-C代码[在项目中混合Swift和Objective-C代码]

在这篇文章中,我将描述如何将Swift静态库导入到Objective-C代码

Objective-C使用者-> Swift静态库

Xcode版本10.2.1

创建Swift静态库

后续Create Swift static library添加:

公开Swift API。在Objective-C中使用Swift的功能[关于]

构建后,您应该找到一个<product_name>-Swift.h文件,该文件应该位于DerivedSources [找不到文件]中

使用Swift静态库的Objective-C使用者

Drag and drop将二进制文件放入Xcode项目[关于]

Link Library[未定义符号] [链接与嵌入]

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[找不到库] [递归路径]

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[找不到模块] [递归路径]

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项目。[未定义符号] 当Xcode询问时,按Create Bridging Header(创建module_name-Bridging-Header.h),并在其中设置此文件的路径

Project editor -> select a target -> Build Settings -> Swift Compiler - General -> Objective-C Bridging Header

将模块导入到Objective-C客户端代码[找不到文件] [module_name]

#import "module_name-Swift.h"

这里有更多例子


0

XCode 11.3.1:

当我想在objc代码中使用Swift内部类时,它不会针对错误“未定义符号”(对于内部类和外部类而言)进行编译,我检查了生成的“ -swift.h”标头,并且两个类都是那里。

尝试了几个小时后,我将内部类转换为普通类,然后进行编译。

我清理项目,删除DerivedData文件夹,然后编译。


1
您是否尝试@objc在内部类的声明之前添加?
dnnagy

谢谢@dnnagy,检查它不是语法问题。
比尔·陈

-1

完成上述所有操作后,我仍然遇到错误。我的问题最终是由于某种原因我需要的Swift文件没有添加到捆绑软件资源中。

我通过转到[MyTarget]>构建阶段>复制捆绑资源来解决此问题,然后单击加号按钮并添加了Swift文件。


复制捆绑资源中不应包含源代码
Bill Chan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.