【问题标题】:Displaying NSDecimal values in XCode debugger在 XCode 调试器中显示 NSDecimal 值
【发布时间】:2013-10-20 10:41:52
【问题描述】:

在使用 XCode 5 进行调试会话期间,我将如何显示 NSDecimal var 的实际值?我找到了this question,但这对我不起作用。输入像{(int)[$VAR intValue]} 这样的摘要描述只会导致消息“摘要不可用”。我应该补充一点,我的 NSDecimals 在一个数组中 (NSDecimal dataPoint[2];)。

使用调试控制台通过上下文菜单或使用 p dataPoint[0] 打印 var 描述只会给我原始的 NSDecimal 视图:

Printing description of dataPoint[0]:
(NSDecimal) [0] = {
  _exponent = -1
  _length = 1
  _isNegative = 0
  _isCompact = 1
  _reserved = 0
  _mantissa = {
    [0] = 85
    [1] = 0
    [2] = 42703
    [3] = 65236
    [4] = 65534
    [5] = 65535
    [6] = 23752
    [7] = 29855
  }
}

【问题讨论】:

    标签: objective-c xcode debugging


    【解决方案1】:

    更新

    在 Xcode 10.0 中,如果 DecimalDictionary<String: Decimal> 中的值(可能在其他情况下),则存在一个 lldb 错误,导致此答案打印错误值。请参阅 this question and answerSwift bug report SR-8989。该错误已由 Xcode 11(可能更早)修复。

    原创

    您可以通过安装将 NSDecimal 的原始位转换为人类可读字符串的 Python 代码来添加 lldb 对格式化 NSDecimal(在 Swift 中为 Foundation.Decimal)的支持。这称为类型摘要脚本,记录在this page of the lldb documentation 上的“PYTHON SCRIPTING”下。

    使用类型摘要脚本的一个优点是它不涉及在目标进程中运行代码,这对于某些目标可能很重要。

    另一个优点是 Xcode 调试器的变量视图在使用类型摘要脚本时似乎比使用在 hypercrypt's answer 中看到的摘要格式更可靠。我对摘要格式有疑问,但类型摘要脚本可以可靠地工作。

    如果没有类型摘要脚本(或其他自定义),Xcode 会显示像这样的NSDecimal(或 Swift Decimal):

    使用类型摘要脚本, Xcode 显示如下:

    设置类型摘要脚本涉及两个步骤:

    1. 将脚本(如下所示)保存在某个文件中。我保存在~/.../lldb/Decimal.py

    2. ~/.lldbinit 添加命令以加载脚本。该命令应如下所示:

      command script import ~/.../lldb/Decimal.py
      

      将路径更改为您存储脚本的位置。

    这是脚本。我也把它保存在this gist

    # Decimal / NSDecimal support for lldb
    #
    # Put this file somewhere, e.g. ~/.../lldb/Decimal.py
    # Then add this line to ~/.lldbinit:
    #     command script import ~/.../lldb/Decimal.py
    
    import lldb
    
    def stringForDecimal(sbValue, internal_dict):
        from decimal import Decimal, getcontext
    
        sbData = sbValue.GetData()
        if not sbData.IsValid():
            raise Exception('unable to get data: ' + sbError.GetCString())
        if sbData.GetByteSize() != 20:
            raise Exception('expected data to be 20 bytes but found ' + repr(sbData.GetByteSize()))
    
        sbError = lldb.SBError()
        exponent = sbData.GetSignedInt8(sbError, 0)
        if sbError.Fail():
            raise Exception('unable to read exponent byte: ' + sbError.GetCString())
    
        flags = sbData.GetUnsignedInt8(sbError, 1)
        if sbError.Fail():
            raise Exception('unable to read flags byte: ' + sbError.GetCString())
        length = flags & 0xf
        isNegative = (flags & 0x10) != 0
    
        if length == 0 and isNegative:
            return 'NaN'
    
        if length == 0:
            return '0'
    
        getcontext().prec = 200
        value = Decimal(0)
        scale = Decimal(1)
        for i in range(length):
            digit = sbData.GetUnsignedInt16(sbError, 4 + 2 * i)
            if sbError.Fail():
                raise Exception('unable to read memory: ' + sbError.GetCString())
            value += scale * Decimal(digit)
            scale *= 65536
    
        value = value.scaleb(exponent)
        if isNegative:
            value = -value
    
        return str(value)
    
    def __lldb_init_module(debugger, internal_dict):
        print('registering Decimal type summaries')
        debugger.HandleCommand('type summary add Foundation.Decimal -F "' + __name__ + '.stringForDecimal"')
        debugger.HandleCommand('type summary add NSDecimal -F "' + __name__ + '.stringForDecimal"')
    

    【讨论】:

    • 如何为我的自定义对象编写相同的脚本?
    【解决方案2】:

    最简单的方法是在调试器中将其变成NSDecimalNumber,即

    po [NSDecimalNumber decimalNumberWithDecimal:dataPoint[0]]
    

    这将创建一个新的NSDecimalNumber 打印一个很好的描述。您问题中的NSDecimal 是8.5。

    (lldb) po [NSDecimalNumber decimalNumberWithDecimal:dataPoint[0]]
    8.5
    

    如果您想在变量视图中显示数字,它的摘要格式将是:

    {[NSDecimalNumber decimalNumberWithDecimal:$VAR]}:s
    

    【讨论】:

    • 非常感谢,即使在评估工具提示中也是如此。但是,在子结构中,它再次不使用设置的摘要格式显示。有什么想法吗?
    • 子结构是什么意思?
    • 当 NSDecimal 是包含在另一个类中的类的成员时,依此类推。
    • 我无法重现。如果你取消引用$VAR,即{[NSDecimalNumber decimalNumberWithDecimal:*&($VAR)]}:s
    • 遗憾的是没有变化。感谢您的尝试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 2016-01-21
    • 2011-01-29
    • 2011-08-05
    • 1970-01-01
    • 2011-12-07
    • 1970-01-01
    相关资源
    最近更新 更多