一尘不染

在xcode8中找不到ModuleName-Swift.h文件

swift

我正在尝试没有运气的Swift和ObjectiveC混合项目。

我的项目由6个目标组成:

  • 应用程式
  • 核心
  • 核心测试
  • 摘要
  • WatchKit扩展
  • WatchKit应用

我已经能够添加一个具有一个目标成员资格(App)的Swift类,并使用从 App-Bridging-Header.h 传递的ObjectiveC代码。“将ObjectiveC转换为Swift代码”范例就像一个魅力。

取而代之的是,我正在苦苦应对“ Swift into ObjectiveC代码”范例。在特定情况下,我需要在ObjectiveC
.m文件中使用一个新的Swift类,该文件是四个目标的成员。

到目前为止,我一直在做的是:

  1. 将一个新的Swift文件添加到Core项目中,指定四个成员资格(App,Core,Summary,WatchKit Ext)
  2. XCode要求为三个项目Core,Summary和WatchKit Ext(自从以前使用以来就已经存在App-Bridging-Header.h)创建 -Bridging-Header.h ,我同意(不知道为什么要在其中创建这些文件我在其中添加Swift类但没关系的同一文件夹
  3. 我创建Swift类,在 类* 之前添加 @objc*
  4. 我去检查是否为所有模块设置了 Objective-C生成的接口头名称 ,是的
  5. 我去检查在所有模块中是否 将Defines Module 设置为 No ,并在主项目中将 Yes 设置为 Yes
  6. 我为所有四个目标写下了 -Swift.h 文件的导入
  7. 在我的Objective-C类中,我尝试使用新的Swift类,显然它可以工作(甚至自动补全)
  8. 我尝试构建项目,但是失败说 -Swift.h 文件未找到

我遵循了AppleMix
and
Match指南
以及许多SO线程,其中包括该线程,显然可以解决我的相同问题,但它不起作用。

还尝试了删除衍生数据以及清理整个项目几次,但都没有运气。

编辑1:更多详细信息

这是我的Swift类导入RealmSwift的声明

@objc class MyClass: Object {}

这是在ObjectiveC中使用Swift类的摘要

MyClass *app = [[MyClass alloc] init];

如果我避免使用#import …- Swift.h,则构建失败会说我正在使用未声明的标识符“ MyClass”,这很合理。

如果我确实使用#import …- Swift.h文件,则说明模块X找不到模块Y,依此类推。

编辑2:Swift模块名称

通过查看每个目标的 SWIFT_OBJC_INTERFACE_HEADER_NAME 属性,我看到它是使用
$(SWIFT_MODULE_NAME)-Swift.h 语法 构建的 。是否需要将 SWIFT_MODULE_NAME 更改为
MODULE_NAME

编辑3:进口

这是.m ObjectiveC文件中Swift标头的导入集。我正在使用在相对的“构建设置”属性中指定的模块名称。注意,由于WatchKit
Extension目标在目标名称中有一个空格,因此它具有“ _”字符。

#import "ProjectName_App-Swift.h"
#import "ProjectName_Core-Swift.h"
#import "ProjectName_Summary-Swift.h"
#import "ProjectName_WatchKit_Extension-Swift.h"

编辑4:-Swift.h文件的交叉可见性

我尝试了以下方法:

  • 仅在目标应用程序中添加了Swift类
  • XCode创建了桥接头
  • 在仅供App使用的ObjectiveC文件中插入#import“ ProjectName_App-Swift.h”
  • 在此文件内使用了Swift类
  • 它编译!而且我可以使用Swift类

当为多个目标定义了Swift类,并且这些多个目标使用了ObjectiveC文件时,它将不起作用。生成错误是这样的:找不到目标X->“ProjectName_TargetY-Swift.h”文件。似乎一个目标无法看到其他目标-Swift.h文件。

我究竟做错了什么?谢谢你的帮助


阅读 503

收藏
2020-07-07

共1个答案

一尘不染

我在Edit 4中所做的假设被证明是正确的。如果项目有多个目标,则无法将“-Swift.h”文件全部导入到一个.m ObjectiveC文件中。

因此,必须采用一种解决方案,即更改 SWIFT_OBJC_INTERFACE_HEADER_NAME的
构建设置,并使其在不同目标上相同。这样做的改变,产生从这个属性的指令 $(SWIFT_MODULE_NAME)-Swift.h
$(PROJECT_NAME)-Swift.h

还可以将“构建设置”中的“产品模块名称”设置设置为在您的模块之间相同(我将其设置为$(PROJECT_NAME)),以便生成的-
Swift.h文件在所有模块中具有相同的名称。 。这消除了添加/检查预处理器宏的需要。

完成此操作后,按Alt并进入“产品”菜单,即可清理构建文件夹。由于标头名称在目标之间共享,现在可以将其一次导入.m
ObjectiveC文件,并且所有目标都可以从Swift类中受益。

如果构建后仍然显示错误,请确保通过Cmd单击其名称可以从XCode到达标头。它应该打开一个包含类似于以下代码的文件:

SWIFT_CLASS("_TtC27ProjectName_Summary11MyClass")
@interface MyClass : NSObject
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

如果需要确保正在生成这些标头,请打开终端并使用此命令

find ~/Library/Developer/Xcode/DerivedData -name "*Swift.h"

您应该为每个目标看到一个标题

这些更改之后发生在我身上的另一个问题是,它开始给我没有碰到的ObjectiveC代码带来错误。问题出在这里,是由于进口的位置:

正是在.m文件顶部的位置,#import隐藏的桥接标头可以有所作为。麻烦的通常迹象是,您收到“未知类型名称”的编译错误,其中未知类型是在Objective-
C中声明的类。解决方案是,在#import隐藏的桥接头文件之前,#import .h文件也包含Objective-
C文件中的未知类型的声明。这样做可能会很烦,特别是如果所讨论的Objective-C文件不需要了解此类时,它可以解决问题并允许进行编译。

最后,代码将在设备和模拟器上编译并运行!

2020-07-07