【问题标题】:Swift to Objective-C header does not contain Swift classesSwift to Objective-C 标头不包含 Swift 类
【发布时间】:2014-07-28 00:07:22
【问题描述】:

我正在尝试在我的 Objective-C 代码中使用 Swift 类,但是我的 Swift 类似乎没有出现在生成的标头中。结果,我的构建因“使用未声明的标识符 'HelloWorld'”而失败。

我使用模板创建了一个名为 TestApp 的项目。

我的目标中有以下构建设置:

  • 产品名称:TestApp
  • 产品模块名称:TestAppModule
  • 定义模块:是

Apple 的文档说要使用 #import <TestApp/TestAppModule-Swift.h>,但这不起作用。

相反,我在“.m”文件中使用#import "TestAppModule-Swift.h"。好像找到了这个。

我可以导航到它,它看起来像这样......

// Generated by Swift version 1.0 (swift-600.0.34.4.5)

#if defined(__has_include) && __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#endif

...etc...

但其中没有定义类。

我在项目中有一个 Swift 文件,看起来像这样......

class HelloWorld {    
    func hello() {
        println("hello world")
    }
}

为什么这不能使用标准头文件位置#import &lt;TestApp/TestAppModule-Swift.h&gt;

如何在该头文件中获取我的 swift 类,这样我就不会收到“未声明的标识符”错误?

【问题讨论】:

    标签: objective-c swift


    【解决方案1】:

    这是我如何让它工作的。你可以看到更大规模的答案here.

    改变这个:

    class HelloWorld {    
        func hello() {
            println("hello world")
        }
    }
    

    收件人:

    @objc class HelloWorld { 
    
        class func newInstance() -> HelloWorld {
            return HelloWorld()
        }
    
        func hello() {
            println("hello world")
        }
    }
    

    然后,在你的 ObjC 文件中:

    #import "TestApp-Swift.h"
    

    然后这样调用:

    HelloWorld * helloWorld = [HelloWorld newInstance];
    [helloWorld hello];
    

    【讨论】:

    • 谢谢!但是请编辑您的答案...“class func newInstance()”
    • 感谢@TroyJ 指出这一点——在 SO 上没有编译器警告 :)
    • 更新:在此处提及@echelon 答案作为对官方答案的评论,以便对某人有所帮助。我已经准备好了一切。 objc 关键字,我的 swift 类是 NSObject 的子类。仍然没有工作。事实证明,正如 echelon 在他的回答中所提到的,我们需要有适当的桥接头,即使我们不会在 Swift 代码中调用 obj-c。很奇怪,但它奏效了。
    • 如果我们想给HelloWorld添加一些实例变量怎么办?例如:var name:Stringvar idNumber:Int?当我这样做时,我会得到各种疯狂的错误,因为初始化不正确。我尝试了六种解决方案 - 没有任何效果。解决这个问题的正确方法是什么?
    • 所以,你在这个问题上的问题有两个@sirab333。 “不正确的初始化”错误是因为 var name: String 是非可选的,这意味着它必须在离开初始化上下文之前具有值。您可以通过将其替换为var name = "" 来获得它而无需构建初始化程序。这应该在 ObjC 中工作。第二个问题是输入Int?。在objective-c 中,intNSInteger 类型永远不能为零,所以这不起作用。将此更改为var idNumber = 0。祝你好运:)
    【解决方案2】:

    tl;dr如果您在 Objective-C 和 Swift 之间进行任何交叉调用,请确保您有一个桥接头。

    我遇到了完全相同的问题:我可以在 DerivedData 中看到 -Swift.h 文件,但它没有提及我的 Swift 类。我正确地导入了头文件,Defines Module 设置是 YES,并且 Product Module Name 是正确的。我尝试删除并重新添加 Swift 文件、清理构建、退出 XCode 等,但没有成功。

    然后我意识到我的项目中没有 -Bridging-Header.h 文件,大概是由于我从以前的项目中拼凑它的方式。应该不是问题,因为我(还)没有从 Swift 调用 Objective-C。但是当我添加一个桥接头,并在构建设置中引用它的路径(Swift 编译器 - 代码生成 - > Objective-C 桥接头)时,它神奇地解决了这个问题——我的 -Swift.h 文件突然充满了 SWIFT_CLASS( ) 天哪!

    所以我猜桥接头是这个过程的基础,即使你没有使用 Swift 的 Objective-C。


    更新:我终于明白了。它与公共/内部访问修饰符有关。不确定我最初是否错过了这一点,或者它是否是 Apple 文档的补充,但它现在明确指出:-

    默认情况下,生成的标头包含 Swift 的接口 用 public 修饰符标记的声明。它还包含那些 如果您的应用程序目标具有 Objective-C 桥接头。

    【讨论】:

    • 即使我创建了一个新的 Swift 文件,也没有创建桥接头。当我想使用来自 Objective C 类的 Swift 类时,这会导致问题。通过手动添加桥接头解决了该问题。谢谢!!
    • 如果我有一个框架,而不是应用程序,我如何使用非公共 swift 类。不支持将桥接头与框架目标一起使用。
    【解决方案3】:

    在您的 .m 文件中使用 #import "TestAppModule-Swift.h" 是正确的。如果您需要在 .h 中引用一个类,请使用 @class 前向声明。

    此外,如果您想使用来自 Objective-C 的 Swift 类,则必须使用 @objc 属性标记 Swift 类。 Xcode 将仅包含在生成的标头中具有属性的类。另见this documentation

    【讨论】:

    • 感谢您指出@objc 注释,我给了您一个赞成票。我还需要从 NSObject 扩展,或者使用 newInstance 类方法。洛根用一个例子给出了一个完整、正确的答案。
    • 非常感谢!在我的 .m 文件顶部添加 -Swift.h 文件为我解决了这个问题!
    • 文档指出:“如果您的 Swift 类是 Objective-C 类的后代,编译器会自动为您添加 @objc 属性。”然而,在最新的 Xcode 7 下,这似乎不再是这种情况(至少对于 UIViewController 子类)。我不得不手动添加注释。
    • 作为参考,使用 Swift 4 编译器,您需要将 @objc 添加到要在 Objective-C 代码中使用的所有 Swift 类方法中!我希望恢复我生命中的几个小时,我试图解决它......
    【解决方案4】:

    类应该声明为@objc public

    【讨论】:

    • 除非你有一个桥接头。有关解释,请参阅我的答案。问题是,有时人们从 Cocoa 框架子类化而没有明确地将子类(和所有被覆盖的方法)标记为 public,因为它的输入更少,并且无论如何它都可以使用默认的 internal 访问。从面向对象的角度来看,这可以说是正确的。当他们想要将类公开给 Objective-C 并且他们没有桥接头时,这会导致问题。
    • 当您的 Swift 代码位于框架 (Pod) 中时,添加公共限定符很重要。
    【解决方案5】:

    更方便的方法是从 NSObject 继承。像这样:

    class HelloWorld: NSObject {    
        func hello() {
            println("hello world")
        }
    }
    

    【讨论】:

      【解决方案6】:

      就我而言,按照 Apple 的指导方针,在我运行项目之前它没有工作。 xcode 编辑器一直标记未知的 swift 类,直到我单击“运行”。构建成功,swift方法奏效了。

      【讨论】:

      • 这也是唯一对我有用的东西。奇怪!
      【解决方案7】:

      在我的情况下,该类没有被编译,因为我首先将它添加到我的测试目标中......在将它添加到我的主要目标(构建阶段 -> 编译源)之后,它被实际编译并添加到头文件。

      TDD 就这么多;-)

      【讨论】:

        【解决方案8】:

        也许您定义了一个与现有 Objective-C 类同名的 Swift 类,如果您想将 Objective-C 代码重构为 Swift,这并不罕见。

        只要您在 Swift 和 Objective-C 中同时定义了一个类,编译器就会完全停止更新桥接头 ("ProductModuleName-Swift.h") - 这也会影响其他桥接 Swift 文件中的后续更改.


        有关如何将 Swift 导入 Objective-C 的一般参考,请参阅: Importing Swift into Objective-C | Apple Developer Documentation

        【讨论】:

          猜你喜欢
          • 2017-01-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多