关于iOS:不能在Objective-C中使用Swift类

Can't use Swift classes inside Objective-C

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

编辑:苹果公司说:"当你将Swift代码导入到Objective-C时,你依靠一个Xcode-generated头文件将这些文件公开给Objective-C.[…]这个头文件的名称是你的产品模块名,然后加上"-Swift.h"。

现在,当我想导入该文件时,它会给出一个错误:

1
2
3
4
5
    //MainMenu.m

    #import"myProjectModule-Swift.h" //Error: 'myProjectModule-Swift.h' file not found

    @implementation MainMenu

这是我的fbmanager.swift文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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的目标C项目中尝试启用Swift。我的"myproject-Swift.h文件创建成功,但我的Xcode没有看到我的Swift-classes文件。所以,我决定创建一个新的基于Xcodeobjc的项目,最终我找到了正确的答案!希望这篇文章能对某人有所帮助:—)

基于xcode objc的项目的逐步快速集成:

  • 创建新的*.swift文件(xcode)或使用finder添加
  • 当xcode询问您时,创建一个Objective-C bridging header
  • 执行您的swift类:

    1
    2
    3
    4
    5
    6
    import Foundation

    // use @objc or @objcMembers annotation if necessary
    class Foo {
        //..
    }
  • 打开生成设置并检查这些参数:

    • 定义模块:YES

      Copy & Paste parameter name in a search bar

    • 产品模块名称:myproject

      Make sure that your Product Module Name doesn't contain any special characters

    • 安装Objective-C兼容头:YES

      Once you've added *.swift file to the project this property will appear in Build Settings

    • Objective-C生成的接口头:myproject-Swift.h

      This header is auto generated by Xcode

    • Objective-C桥接头:$(SRCROOT)/myproject-Bridging-Header.h
  • 在您的*.m文件中导入swift接口头文件

    1
    #import"myproject-Swift.h"

    Don't pay attention to errors and warnings.

  • 清理并重建Xcode项目
  • 利润!

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

    确保您的swift类被标记为@objc或继承自(直接或间接)从NSObject派生的类。

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


    允许xcode进行工作,不要手动添加/创建swift头。把@objc加到你的swift类前。

    1
    @objc class YourSwiftClassName: UIViewController

    在项目设置中,搜索以下标志并将其更改为"是"(项目和目标)

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

    然后清理项目并构建一次,在构建成功(可能应该)之后,在objective-c class.m文件的头文件下面导入

    1
    #import"YourProjectName-Swift.h"

    嘘声!


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

    自动生成的头文件的import语句与app目标看起来有点不同。除其他答案中提到的其他内容外,使用

    1
    #import <ProductName/ProductModuleName-Swift.h>

    而不是

    1
    #import"ProductModuleName-Swift.h"

    根据苹果公司关于框架目标混合和匹配的文档。


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

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


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

    任务:

  • 在objective-c类中使用swift枚举
  • 在swift类中使用objective-c枚举
  • 全样本1。使用swift枚举的objective-c类

    ObjcClass.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #import <Foundation/Foundation.h>

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

    @interface ObjcClass : NSObject

    + (void) PrintEnumValues;

    @end

    ObjcClass.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #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

    检测目标C代码中的Swift代码

    在我的示例中,我使用swiftcode.h在objective-c中检测swift代码。此文件自动生成(我没有在项目中创建此头文件的物理副本),您只能设置此文件的名称:

    enter image description here

    enter image description here

    If the compiler can not find your header file Swift code, try to compile the project.

    2。使用Objective-C枚举的Swift类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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项目xcode中添加objective-c文件时,将建议您创建桥接头文件。

    enter image description here

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

    enter image description here

    Bridging-Header.h

    1
    #import"ObjcClass.h"

    用法

    1
    2
    3
    4
    5
    #import"SwiftCode.h"
    ...
    [ObjcClass PrintEnumValues];
    [SwiftClass PrintEnumValues];
    [SwiftClass PrintEnumValue:ObjcEnumValue3];

    结果

    enter image description here

    更多样品

    Full integration steps Objective-c and Swift described above. Now I will write some other code examples.

    三。从目标C代码调用swift类

    Swift class

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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 code (calling code)

    1
    2
    3
    4
    SwiftClass *obj = [[SwiftClass alloc] initWithStringValue: @"Hello World!"];
    [obj printValue];
    NSString * str = obj.stringValue;
    obj.stringValue = @"HeLLo wOrLd!!!";

    结果

    enter image description here

    4。从swift代码调用objective-c类

    Objective-C class (ObjcClass.h)

    1
    2
    3
    4
    5
    6
    7
    #import <Foundation/Foundation.h>

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

    ObjcClass.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #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 code (calling code)

    1
    2
    3
    4
    5
    if let obj = ObjcClass(stringValue: "Hello World!") {
        obj.printValue()
        let str = obj.stringValue;
        obj.stringValue ="HeLLo wOrLd!!!";
    }

    结果

    enter image description here

    5。在目标C代码中使用swift扩展

    Swift extension

    1
    2
    3
    4
    5
    extension UIView {
        static func swiftExtensionFunc() {
            NSLog("UIView swiftExtensionFunc")
        }
    }

    Objective-C code (calling code)

    1
    [UIView swiftExtensionFunc];

    6。在swift代码中使用objective-c扩展

    Objective-C extension (UIViewExtension.h)

    1
    2
    3
    4
    5
    #import <UIKit/UIKit.h>

    @interface UIView (ObjcAdditions)
    + (void)objcExtensionFunc;
    @end

    UIViewExtension.m

    1
    2
    3
    4
    5
    @implementation UIView (ObjcAdditions)
    + (void)objcExtensionFunc {
        NSLog(@"UIView objcExtensionFunc");
    }
    @end

    Swift code (calling code)

    1
    UIView.objcExtensionFunc()


    我也有同样的问题,结果发现模块名称中的特殊符号被xcode替换(在我的例子中,破折号最后是下划线)。在"项目设置"中,选中"模块名称"以查找项目的模块名称。之后,使用ModuleName-Swift.h或在设置中重命名模块。


    文件是自动创建的(这里是Xcode6.3.2)。但您不会看到它,因为它在派生数据文件夹中。用@objc标记swift类后,编译,然后在派生数据文件夹中搜索Swift.h。你应该在那里找到那个快速的标题。

    我有个问题,xcode把我的my-Project-Swift.h改名为my_Project-Swift.hxcode不喜欢".""-"等符号。使用上面的方法,您可以找到文件名并将其导入到Objective-C类中。


    只包括#在.m或.h文件中导入"myproject swift.h"

    另外,你在档案检查员中找不到"myproject swift.h",它是隐藏的。但它是由应用程序自动生成的。


    有两个条件,

    • 使用目标C文件中的swift文件。
    • 使用Swift文件中的目标C文件。

    因此,为此,您必须遵循以下步骤:

    • 将您的swift文件添加到Objective-C项目中,反之亦然。
    • 创建头文件(.h)。
    • 转到"生成设置",并通过搜索执行以下步骤,

    • 搜索文本"brid"并设置头文件的路径。
    • "定义模块":是。
    • "始终嵌入Swift标准库":是。
    • "Install objective-c compatibility header":是。

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

    使用目标C文件中的swift文件。

    在这种情况下,首先在swift文件中的类之前写"@objc"。

    在那之后,在你的目标C文件中,写下这个,

    1
      #import"YourProjectName-Swift.h"

    使用Swift文件中的目标C文件。

    在这种情况下,在你的头文件中,写下这个,

    1
      #import"YourObjective-c_FileName.h"

    我希望这对你有帮助。


    @SIG答案是最好的答案之一,但是它对我来说不适用于旧项目(不是新项目!),我需要一些修改。经过许多变化,我找到了我的食谱(使用xcode 7.2):

  • 产品模块名称:$(产品名称:C99extIdentifier)
  • 定义模块:否
  • 嵌入内容包含swift:no
  • 安装Objective-C兼容性头:是
  • objective-c桥接头:projectname桥接头.h
  • 最后一点(5)至关重要。我只把它放在第二部分(目标字段),项目字段应该留空:enter image description here,否则,它不会为我生成正确的"project swift.h"文件(不包括swift方法)。


    在我的例子中,除了这些步骤:

  • 产品模块名称:MyProject
  • 定义模块:是
  • 嵌入内容包含swift:是
  • 安装Objective-C兼容性标题:是
  • objective-c桥接头:$(srcroot)/sources/swiftbridging.h
  • 我需要将该类作为公共类来创建ProductName Swift.h文件:

    1
    2
    3
    4
    5
    6
    7
    import UIKit

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

    我也遇到了同样的问题,最后看来他们并不是同一个目标。objc类附加到target1和target2,swift类只附加到target1,在objc类中不可见。

    希望这能帮助别人。


    我刚刚发现向项目添加一个swift文件目录是行不通的。您需要先为目录创建一个组,然后添加swift文件…


    好吧,在阅读了所有的评论,并尝试阅读和再次尝试之后,我设法在我的大型obj-c项目中加入了swift类。所以,谢谢你的帮助。我想分享一个帮助我更好地理解这个过程的提示。在.m类中,转到swift目标名称的导入行import"mytargetname swift.h"然后点击键:

    命令+鼠标单击->跳转到定义enter image description here

    在这里,您可以看到从swift到obj-c的所有翻译,然后您将发现obj-c中重新声明的各种函数。希望这条建议对你的帮助和对我的帮助一样多。


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


    我不需要更改构建中的任何设置,也不需要将@obj添加到类中。

    我所要做的就是创建桥头,当我在Objective-C项目中创建Swift类时自动创建桥头。然后我就不得不这么做

    导入"bedtime swift.h"<-在需要使用该swift文件的objective-c文件中。

    我有一个问题,我将向我的objective-c桥接头添加类,在那些导入的objective-c头中,它们试图导入swift头。它不喜欢那样。

    因此,在所有使用swift但也是桥接的objective-c类中,关键是确保在头文件中使用forward类声明,然后在.m文件中导入"*-swift.h"文件。


    我的问题是,Xcode创建了网桥文件后,我卡住了,但头文件名myprojectname swift.h中仍然有错误。

    1.我登记终端并搜索所有自动创建的Swift Bridge文件:

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

    您可以看到Xcode创建了什么。

  • 在我的例子中,我的项目名称中有空格,xcode替换为"u"

  • 我的问题是-swift.h文件的自动生成无法理解CustomDebugStringConvertible的子类。我将类改为nsObject的子类。之后,-swift.h文件正确地包含了类。


    在做了以上所有的事情之后,我仍然有错误。我的问题是我需要的swift文件由于某种原因没有添加到包资源中。

    我通过转到[我的目标]>构建阶段>复制捆绑资源修复了这个问题,然后单击加号按钮并添加了Swift文件。