objective-c - 行代码在 lldb `p` 中工作,代码在托管单元测试中失败

标签 objective-c swift frameworks lldb djinni

我发现很多关于 NSArray element failed to match the Swift Array Element type 错误的帖子。但是,我仍然无法让它工作。 我怀疑问题与我创建的 Objective-C 框架绑定(bind)有关,而不是转换问题。其中,我不明白的一件事是为什么代码在 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 works

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

getMuses 函数由 djinni 包装,使用我编写的模块映射将专有的 Objective-C 框架绑定(bind)到 swift。这是我写的模块图。我还没有遇到其他函数绑定(bind)的问题(请参阅评论)。删除 [system] 属性不会触发任何其他警告。

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

djinni 生成的声明:

public func getMuses() -> [IXNMuse]

原始 objc 声明:

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

由于框架是专有的,因此定义不可用。

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

最佳答案

编辑后的答案

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

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

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

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

原始答案

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

由于我不明白的原因,我得到了 IXNMuse 类的双重定义。这两个定义之间的 Swift 冲突是导致 NSArray 元素无法匹配 Swift 数组元素类型 错误的原因。

修复程序

当我执行以下过程时,问题消失了:

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(我相信它不会将两个目标链接到具有三角依赖的相同框架是错误的)。就这样,我又回到了刚开始写题时的状态。问题没有再次出现,测试仍然通过。

结论

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

关于objective-c - 行代码在 lldb `p` 中工作,代码在托管单元测试中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49604722/

相关文章:

java - 如何构建自己的java框架

c - "opening a file"是否意味着将其完全加载到内存中?

ios - 将电话号码转换为带有国家/地区代码的国际 iOS 号码

ios - 如何在 VFL 中编写 topLayoutGuide 约束

arrays - 如何让你的tableView在你的tableView顶部显示新的或更新的元素 PT.2

php - 使用 foreach 循环进行搜索不返回第一个匹配项

ios - SpriteKit - 如何添加具有特定距离的对象

ios - 自定义键盘返回标题设置 IOS8

ios - UICollectionView 中的 IBOutlets 为 nil - Swift

html - Bulma.io 全高英雄背景