Swift Frameworkがlldbのメソッド拡張の「あいまいな使用」を返す


8

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)

すべてが正常にコンパイルおよび実行されますが、サブプロジェクトでデバッグセッションを実行するerror: ambiguous use of場合、lldbコマンドラインから呼び出されると、「フレームワーク」のすべての拡張機能が返されます。これはアイデアを与えるためのコードサンプルです:

macOsコマンドラインプロジェクトを作成し、新しいターゲット 'MagicFramework'をSpells.swiftファイルに追加します(ファイルがMain&MagicFrameworkに表示されることを確認してください)

import Foundation

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

次に、サブプロジェクト「ウィザード」を作成し、wizard.swiftファイルで(ウィザードのみに表示):

import Foundation
import MagicFramework


public class Tadaa {

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

ウィザードのmain.swiftファイルに、以下を追加します。

import Foundation

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

print(aa)

次の構造が必要です。

-> Main project
----> MagicFramework
----> Wizard subproject

次に、ブレークポイントをオンにspell.castSpell()して「ウィザード」サブをビルドして実行しTadaaます。lldbプロンプトで、次のように入力します。

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

なぜ??この問題はXcode 10では発生しませんでした。

回答:


7

私の控えめな意見では、これはバグにすぎません。

あなたがあなたの質問で与えている例を設定したら、私は問題を再現できます。

ブレークポイントで、私は得る

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

あなたが説明したように。

ただし、castSpelllldbで関数を検索すると、次のようになります。

(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はちょうど1つの一致を検出したことを意味しMagicFrameworkます。つまり、ライブラリ内の拡張子です。したがって、これがあいまいになる理由はありません。

完全を期すために、spellllbdが認識する変数の型も確認しました。

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

つまり、lldb はタイプが文字列であることを認識しています。それは知っている機能があるというcastSpell拡張子で定義されているが、それは言った機能の正確に一つの実装を知っています。しかし、それでもエラーメッセージが表示されます。

したがって、ここで必要不可欠なものを欠落していない限り、これはlldbのバグでなければなりません。


正しいように聞こえます:)詳細をありがとうございます!それを回避する方法があることを知っていますか?
Alex

1
Alexさん、申し訳ありませんが、動的libでこれを回避する方法はわかりません。ただし、MagicFrameworkを静的ライブラリにできる場合は問題ありません(ターゲットのビルド設定のMach-Oタイプ、この設定を変更した後、必ず製品->クリーンビルドフォルダーを実行してください)
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) 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.