Swift框架在lldb中返回“方法扩展的使用不明确”。

9
我已经升级到Xcode 11和Swift 5,并遇到一个问题,即在框架中提供方法扩展时会出现问题。更具体地说,在像这样结构化的项目中:
-> Main Project
-> Framework created from sources in 'Main Project'
-> Subproject using the above Framework (Sources packaged in the framework are not visible to the sub-project)

一切编译和运行都很顺利,但在对子工程进行调试会话时,从lldb命令行调用“Framework”中的所有扩展名都返回“error:ambiguous use of”。以下是一个代码示例,以便了解情况:
创建一个macOS命令行项目,并添加一个新目标,“MagicFramework”,并在文件Spells.swift中(确保该文件对“Main”和“MagicFramework”可见)。
import Foundation

extension String {
    public func castSpell() -> String {
        return "✨ " + self
    }
}

然后创建一个名为'Wizard'的子项目,并在一个名为wizard.swift的文件中(仅对Wizard可见):

import Foundation
import MagicFramework


public class Tadaa {

    public func magic(spell:String) -> String {
        return spell.castSpell()
    }
}

在Wizard的main.swift文件中添加:
import Foundation

let aa = Tadaa().magic(spell: "this is magic")

print(aa)

你应该有以下结构:
-> Main project
----> MagicFramework
----> Wizard subproject

然后构建并运行"Wizard"子程序,在Tadaa中的spell.castSpell()上设置断点。在lldb提示符下,输入:

(lldb)po spell.castSpell()
error: <EXPR>:3:1: error: ambiguous use of 'castSpell()'
spell.castSpell()

为什么??这个问题在Xcode 10中没有发生过。

2个回答

8

依我拙见,这只能是一个bug。

如果按照你问题中提供的示例进行设置,我可以复现这个问题。

在断点处,我得到了以下信息:

(lldb) po spell.castSpell()
error: <EXPR>:3:1: error: ambiguous use of 'castSpell()'
spell.castSpell()
^

就像你所描述的一样。

然而,如果我在 lldb 中查找函数 castSpell ,我会得到:

(lldb) image lookup -vn castSpell
1 match found in /Users/lameyl01/Library/Developer/Xcode/DerivedData/Main-dsjbnoyousgzmrdnqxtxoeyeyzpv/Build/Products/Debug/MagicFramework.framework/Versions/A/MagicFramework:
        Address: MagicFramework[0x0000000000000ab0] (MagicFramework.__TEXT.__text + 0)
        Summary: MagicFramework`(extension in MagicFramework):Swift.String.castSpell() -> Swift.String at Spells.swift:12
         Module: file = "/Users/lameyl01/Library/Developer/Xcode/DerivedData/Main-dsjbnoyousgzmrdnqxtxoeyeyzpv/Build/Products/Debug/MagicFramework.framework/Versions/A/MagicFramework", arch = "x86_64"
    CompileUnit: id = {0x00000000}, file = "/Users/lameyl01/tmp/Main/MagicFramework/Spells.swift", language = "swift"
       Function: id = {0x100000038}, name = "(extension in MagicFramework):Swift.String.castSpell() -> Swift.String", mangled = "$sSS14MagicFrameworkE9castSpellSSyF", range = [0x000000010033fab0-0x000000010033fb21)
       FuncType: id = {0x100000038}, byte-size = 8, decl = Spells.swift:12, compiler_type = "() -> ()"
         Blocks: id = {0x100000038}, range = [0x10033fab0-0x10033fb21)
      LineEntry: [0x000000010033fab0-0x000000010033fabf): /Users/lameyl01/tmp/Main/MagicFramework/Spells.swift:12
         Symbol: id = {0x00000005}, range = [0x000000010033fab0-0x000000010033fb21), name="(extension in MagicFramework):Swift.String.castSpell() -> Swift.String", mangled="$sSS14MagicFrameworkE9castSpellSSyF"
       Variable: id = {0x100000055}, name = "self", type = "Swift.String", location = DW_OP_fbreg(-16), decl = Spells.swift:12

这意味着lldb已经找到了唯一的匹配项:位于MagicFramework库中的扩展。因此,这不应该有歧义。

为了完整起见,我还检查了变量spell在lldb中看到的类型:

(lldb) frame variable spell
(String) spell = "this is magic"

因此,总结一下: lldb知道类型是String。它知道扩展中定义了一个名为castSpell的函数,并且知道该函数的唯一实现。但仍然显示错误消息。 因此,除非我遗漏了什么重要的内容,否则这必须是lldb的一个错误。

听起来没问题 :) 非常感谢您提供的详细信息!您知道有没有办法绕过这个问题吗? - Alex
1
抱歉Alex,我不知道如何解决动态库的问题。但如果你可以把你的MagicFramework变成静态库,那么这个问题就不存在了(在目标的构建设置中使用Mach-O类型,在更改此设置后一定要运行Product->Clean Build Folder)。 - Lutz
@Alex和Lutz,感谢你们的问题和答案。我找到了一个可怕的解决方法,但是它仍然是一个解决方法。我暂时添加了一个类D,其中包含静态方法,这些方法调用扩展方法(以对象作为参数),然后从那里调用扩展;这将帮助我度过难关,直到问题得到解决。 - aepryus

0

我在我的扩展中遇到了同样的问题。在我的情况下,有一个单一的函数,在调试时我经常使用它,所以我创建了一个全局函数,在你的情况下,它只需要接受字符串并调用该扩展即可。这与@aepryus在第一个答案的评论中指出的非常相似。

import Foundation

extension String {
    public func castSpell() -> String {
        return "✨ " + self
    }
}

func castSpell(_ string: String) -> String {
    return string.castSpell()
}

然后像这样使用它:

(lldb) po castSpell("this is magic")
"✨ this is magic"

(lldb) 

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