【问题标题】:Line code works in lldb `p`, code fails in hosted unit test行代码在 lldb `p` 中工作,代码在托管单元测试中失败
【发布时间】:2018-04-02 02:53:34
【问题描述】:

我发现了很多关于 NSArray element failed to match the Swift Array Element type 错误的帖子。但是,我仍然无法让它工作。 我怀疑该问题与我制作的目标 C 框架绑定有关,而不是强制转换问题。其中,我不明白的一件事是为什么代码在 lldb p 指令中工作,而不是作为在主机 ios 应用程序中执行的单元测试(否则我无法测试它,因为代码需要 B-LE 而不是可从 iphone 模拟器获得)。

class onceFirstMuseConnected: IXNMuseListener {
    let museManager: IXNMuseManager
    let callback: (_ muse: IXNMuse) -> Void

    init(museManager: IXNMuseManager, callback: @escaping (_ muse: IXNMuse) -> Void) {
        self.museManager = museManager
        self.callback = callback
        museManager.setMuseListener(self)
        museManager.startListening()
    }

    func museListChanged() {
        let muses: [IXNMuse] = museManager.getMuses()
        guard muses.count > 0 else {
            return
        }
        let _ = muses.first!.getName() // <<<< `muses.first` fails as well as any other
                                       //      kind of array's item access with "Fatal
                                       //      error: NSArray element failed to match the
                                       //      Swift Array Element type"
    }
}

奇怪的是,如下图所示,我能够使该行在 lldb 中工作。

编辑:由于我有多个反对意见,我希望能解释一下为什么 lldb 行在主执行崩溃时在评论中起作用。如果是类型转换问题,我认为 lldb 行将不起作用。我发现的相关问题都没有回答这个问题。我承认我是一个 swift/objc 新手,如果不是与 objc-swift 框架映射过程相关的问题,可能有一些我不明白的明显问题。

getMuses 函数由 djinni 包装,使用我编写的模块映射将专有目标 C 框架绑定到 swift。这是我写的模块图。我对其他函数绑定没有任何问题(参见 cmets)。删除 [system] 属性不会触发任何额外的警告。

module Muse [system] {
    header "Muse.framework/Headers/Muse.h"
    export *
}

djinni 生成的声明:

public func getMuses() -> [IXNMuse]

原始的objc声明:

 - (nonnull NSArray<IXNMuse *> *)getMuses;

定义不可用,因为框架是专有的。

返回的指针不太可能为 null 或指出错误的内存地址,因为 lldb 对屏幕截图中显示的 getName 方法的调用不会给出正确的结果。

【问题讨论】:

  • 我假设您不能将 IXNMuse 转换为 _。尝试使用 let object = muses.first 作为? IXNMuse
  • 不幸的是,这不起作用,我得到了同样的错误。
  • 另外,快速帮助(alt + 点击first)识别类型IXNMuse(它在声明中声明var first: IXNMuse? { get }
  • 我必须为 muse 库编写模块映射(从目标 c 框架包装)。我的目标是一个快速的框架。我想知道这个问题是否相关,因为我在类似的非框架代码中没有这个问题,但我不得不承认我是两种语言的完全新手,所以这也可能完全不相关。
  • 感谢您添加声明。但没有包含任何信息,我可以找到一些线索来解决您的问题。如果将print(type(of: (muses as NSArray).firstObject!)) 放在导致崩溃的行之前,您会得到什么?

标签: objective-c swift frameworks lldb djinni


【解决方案1】:

编辑答案

Muse.framework 是一个静态框架。 XCTests 内置在宿主应用程序中嵌入的包中。在我的设置中,涉及 3 个目标:我开发的框架、用于测试的主机应用程序和 XCTest 包。

静态框架在目标二进制文件中嵌入符号使用

为避免重复符号问题,静态框架应仅链接到目标框架**,而不是 xctest 包或测试主机应用程序,它们通过链接目标框架来过渡链接符号。

为确保目标框架嵌入其静态链接框架依赖项的所有符号,必须将 -force_load 标志后跟静态依赖项路径添加到目标框架链接选项 (OTHER_LDFLAGS) .

原答案

致谢 OOPer 在问题评论中寻求帮助。

由于我不明白的原因,我的 IXNMuse 类有双重定义。两个定义之间的 Swift 冲突是我遇到 NSArray element failed to match the Swift Array Element type 错误的原因。

修复程序

当我执行以下步骤时问题消失了:

A.在测试以下代码时

let muses: NSArray = museManager.getMuses() as NSArray
let muse: IXNMuse = muses.firstObject! as! IXNMuse

我在运行时收到

Could not cast value of type 'IXNMuse' (0x103cfa180) to 'IXNMuse' (0x103e965e0).

B. 我有两个import Muse 语句,一个在我的测试文件中,一个在我的框架目标源文件之一中。 从测试文件中删除import Muse 语句(使用相关代码)。这通过删除双重 IXNMuse 定义让测试通过。

C. 我从测试目标的Link Binary with Libraries 中删除了Muse.framework,因为它已经包含在我测试的框架目标中。我从刚刚删除的测试文件中放回了import Muse 语句(带有相关代码,因为我仍然需要它)。 即使在两个目标源文件中都导入了双 Muse,测试仍然通过。

D. 我将Muse.framework 放回了我的测试目标的Link Binary with Libraries(我相信让两个目标链接具有三角依赖关系的同一个框架不是错误) .因此,我回到了与我最初写问题时的状态相似的状态。该问题没有再次出现,测试仍然通过。

结论

我仍然有点困惑,为什么我一开始会遇到这个问题。可能我的状态并不完全一样,并且在更改我不记得的链接配置的过程中做了一些事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    • 2013-08-12
    • 2011-01-31
    • 1970-01-01
    • 2017-05-31
    • 1970-01-01
    相关资源
    最近更新 更多