在XCode调试器中显示NSDecimal值

时间:2013-10-12 11:21:46

标签: objective-c xcode debugging

在使用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
  }
}

2 个答案:

答案 0 :(得分:3)

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

po [NSDecimalNumber decimalNumberWithDecimal:dataPoint[0]]

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

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

如果您希望在变量视图中显示该数字,则其摘要格式为:

{[NSDecimalNumber decimalNumberWithDecimal:$VAR]}:s

答案 1 :(得分:2)

更新

如果DecimalDictionary<String: Decimal>中的值(可能在其他情况下),则存在一个lldb错误,该错误会使此打印错误的值。参见this question and answerSwift bug report SR-8989

原始

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

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

另一个优点是,与hypercrypt's answer中所见的摘要格式相比,使用类型摘要脚本的Xcode调试器的变量视图似乎更可靠地工作。我在摘要格式上遇到麻烦,但是类型摘要脚本可以可靠地工作。

没有类型摘要脚本(或其他自定义),Xcode显示如下所示的NSDecimal(或Swift Decimal):

before type summary script

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

after type summary script

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

  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"')