iOS Xcode SPM无法解译超类。

11
我的应用程序由许多项目(框架)组成,每个主要功能都有一个项目,以及一个通用框架,其中包含我需要在多个功能中访问的各种内容。我正在使用Xcode 11的Swift Package Manager添加依赖项。通用框架包含RxSwift依赖项,我在整个项目中都使用它。当我尝试在任何一个功能框架中使用RxTest时,我遇到了问题。如果我直接将RxTest通过SPM添加到测试目标并运行测试,我会得到“failed to demangle superclass of 'class name' from mangled name 'other class name'”和许多“Class 'class name' is implemented in both 'common framework path' and 'test target path'” 的错误。所有这些类都与Rx相关。'failed to demangle'错误会使测试崩溃,并且仅当我尝试初始化RxTest类时才会出现。如果我将RxTest添加到通用框架中,则测试运行正常,但是当我运行应用程序时,会出现“dyld: Library not loaded: @rpath/XCTest.framework/XCTest”的错误。这是有道理的,因为我正在将一个测试框架添加到非测试框架中,这不是一件好事。所以基本上,我无法获得既能运行应用程序又能运行测试的配置。要么应用程序运行,要么测试运行。

我该如何让它工作?是否有一种方法只在测试目标上构建时在通用框架上包含 RxTest?或者 RxTest 只应该包括在测试目标上,我可能错失了某些配置吗?

3个回答

2

Xcode与SPM依赖项目前无法处理同一SPM依赖项在相互依赖的多个目标中的情况。目前每个依赖项只能存在于单个目标中。目前我不知道原因,但我将尝试更深入地调查,并在尚未提交错误报告的情况下提交错误报告。


嗨,有没有找到更多的线索? - janh
你有关于这个的任何发现吗? - bogen
目前还没有任何内容 :) 问题实际上是,它在目标中静态链接了依赖项。 - Zdeněk Topič

1
您的问题可能是因为该库使用了静态链接而不是动态链接。在SwiftPM中,如果您愿意,可以将库指定为静态或动态,或者您可以让构建系统决定哪个是大多数软件包所做的。当使用SwiftPM构建时,Xcode似乎更喜欢静态方法,这会导致您遇到的构建问题。
如果您将Package.swift修改为将RxTest作为动态库,则应该可以解决该问题。您可以通过克隆RxSwift并修改此行来轻松测试:
.library(name: "RxTest", targets: ["RxTest"]),

转换为:

.library(name: "RxTest", type: .dynamic, targets: ["RxTest"]),

然后将RxSwift的本地副本拖入Xcode项目导航器中。这样它就会使用您本地的软件包副本,而不是Xcode克隆的软件包。
完成此操作后,您可以将其链接到任何需要的目标,并且应该可以正常工作。如果这确实解决了问题,那么您的长期解决方案可能是:
1)创建一个分支,将其更改为动态库。
2)说服RxSwift社区将其产品更改为动态或出售动态版本以补充默认版本。
3)不要在多个位置使用RxTest或类似的东西。
值得注意的是,Xcode 11.3及更早版本不支持使用动态Swift Packages进行存档。因此,如果您选择动态路线,则必须等待Xcode 11.4。

克隆并修改每个依赖项对我来说似乎不是一个解决方案。大多数包都使用默认类型,我认为这在某种程度上是自动的,并且基于某种原因选择静态链接。由于该软件包链接到多个目标,我期望它会选择动态链接。 - Zdeněk Topič
是的,这很痛苦。我同意动态行为应该是预期的行为。我们能做的最好的事情就是向苹果提交反馈请求来改变这种情况。 - bscothern

0

解决方法:

我也遇到了同样的问题。我的项目配置如下:

  • 工作区
    • ProjectAppOne
      • AppTargetOne(嵌入并签署FrameworkTarget)
    • ProjectAppTwo
      • AppTargetTwo(嵌入并签署FrameworkTarget)
    • ProjectCoreFramework
      • FrameworkTarget
      • testsTareget
      • SPM 依赖项(包括 RxSwift)

我的解决方法是:

  1. 复制 FrameworkTarget 并创建一个 FrameworkTargetT(确保两者都能够无误地构建)。
  2. FrameworkTarget 仍然用于构建应用程序目标,因此请确保它是应用程序目标导入中唯一使用的。
  3. 将 RxTest 添加到 FrameworkTargetT 中。
  4. FrameworkTarget 中删除 RxTest。
  5. 在测试中设置 @testable import FrameworkTagetT
  6. 调整 FrameworkTarget 以不运行 testsTarget。
  7. 设置 FrameworkTargetT 以运行 testsTarget
  8. 调整涉及测试目标并直接调用 FrameworkTarget 的 CI fastlane/scripts。

最终项目结构如下:

  • 工作区
    • ProjectAppOne
      • AppTargetOne(嵌入并签署FrameworkTarget)
    • ProjectAppTwo
      • AppTargetTwo(嵌入并签署FrameworkTarget)
    • ProjectCoreFramework
      • FrameworkTarget
      • FrameworkTargetT
      • testsTareget
      • SPM依赖项(包括RxSwift)

我认为这不是理想的解决方案,因为在代码或测试中导入错误的框架很容易,所以请仔细检查。但是,在等待SPM团队解决问题时,它可以被使用和轻松删除。如果您已经有了一个分离的框架代码,那么这也很容易。

附注:您需要记住将每个新文件添加到FrameworkTargetFrameworkTargetT两个目标中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接