38

How can I plot out variable's value in a Swift App with LLDB?

Earlier it was like po variable_name

Now I usually get some nasty error, like:

(lldb) po a
error: <EXPR>:11:5: error: use of unresolved identifier '$__lldb_injected_self'
    $__lldb_injected_self.$__lldb_wrapped_expr_2(     
    ^
János
  • 32,867
  • 38
  • 193
  • 353
  • 3
    Yep, debugging in Swift is currently reliant on `println`. – Jack Jul 16 '14 at 16:57
  • I had a similar debugger error that only took place when trying to inspect `let` constants; see my question about it [here](http://stackoverflow.com/questions/26189424/how-to-view-value-of-swift-let-constant-in-xcode-6-debugger)—it turned out to be a bug in Xcode 6. – George WS Oct 11 '14 at 05:13
  • There seems to be a call for code samples / projects that exhibit these problems, from person(s) of the compiler team: https://devforums.apple.com/message/1106278#1106278 . Any contribution to that cause would surely be appreciated by all (and would most certainly be a jolly-good-fellow) – Chris Conover Mar 04 '15 at 02:03
  • I have made some tests with current Xcode and Swift testing printing with object. Maybe that will be helpful somehow. – Julian Oct 21 '15 at 08:36

4 Answers4

19

That error sounds like it might be because DWARF is not telling LLDB where to find your self object. Given the nature of Swift, LLDB needs to know the type of self in order to be able to inject an expression inside your local scope. One way to find out if that is your problem is to do at the LLDB prompt:

(lldb) frame variable -L self

You are probably going to not see a location for it. Worth filling a bug report for, just to track your specific repro case.

Anyway, to get to the bulk of your question. In Swift, there is no language-sanctioned mechanism for "print description" like for ObjC, so while you can type po self, unless self is an Objective-C type, you will pretty much see the same thing that "p self" or even "frame variable self" would tell you - which is entirely based on the LLDB data formatters mechanism. If you want to hook into that to customize the way your Swift objects look, the obligatory reference is: http://lldb.llvm.org/varformats.html

ricardopereira
  • 11,118
  • 5
  • 63
  • 81
Enrico Granata
  • 3,303
  • 18
  • 25
  • 4
    It is freaking annoying that final Xcode 6 is released and they couldn't implement basic feature to watch any variable's value during debugging. – János Sep 22 '14 at 08:19
  • @enrico: What is the current state of the art for getting Swift symbols - is po expected to work at all on pure swift objects? Is there a different means of getting data, and are there special build settings that are needed for this? Thanks! – Chris Conover Feb 07 '15 at 00:38
  • "frame variable" doesn't get same result as print description of object. It prints almost useless trash. – poGUIst May 27 '16 at 12:36
  • @poGUIst that's unfortunate - can you please give me more details about this? what data types are involved? what does 'po' give you that frame variable does not? – Enrico Granata May 31 '16 at 22:34
  • frame variable displays memory addresses of member references, while 'po' executes 'description' method of NSObject descendant which usually much more informative. Actually i'll try to directly call 'description' method. May be it helps. 8) – poGUIst Jun 21 '16 at 21:50
4

I have made a few tests to figure out how it works with Swift, results surprised me a bit. With ObjC objects po calls debugDescription which by default calls description. That is clear. Unfortunately the same doesn't apply while working with Swift classes. I focused on objects rather than on printing single variables.

To make it working (po command in lldb) I had to override description. Below code I used for testing:

class Test : NSObject
{
    var name : String?
    var surname : String?

    override var debugDescription : String{
        return "debugDescription method"
    }

    override var description : String {
        return "description Method"
    }
}

Testing:

let test = Test()
test.name = "name"
test.surname = "surname"

(lldb) po test
description Method

(lldb) p test
(DebugTest.Test) $R1 = 0x00007fce11404860 {
  ObjectiveC.NSObject = {
    isa = DebugTest.Test
  }
  name = "name"
  surname = "surname"
}

(lldb) po dump(test)
▿ DebugTest.Test #0
  - super: debugDescription method
  ▿ name: name
    - Some: name
  ▿ surname: surname
    - Some: surname
description Method

(lldb) po print(test)
description Method

The thing that surprised me is that po on Swift objects calls description rather than debugDescription that differs from ObjC.

EDIT

To make it acting like with ObjC, Your class have to implement CustomDebugStringConvertible and then po will call debugDescription, which by default calls description. The only thing which have to be changed in my example would be adding:

class Test : NSObject, CustomDebugStringConvertible

Reference

Checked with XCode 7.0.1 and iOS SDK 9, Swift 2.0

Julian
  • 9,299
  • 5
  • 48
  • 65
2

Great answers in this page about swift defaulting to return the description when running lldb) po

If it helps, when hitting errors with lldb and Swift objects I alway tried to be in a good place.

First, tell lldb you are in a Swift context (not Objective-C):

(lldb) settings set target.language swift

Then I would always double-check I had imported the Framework..

lldb) exp import WebKit
(lldb) expr let $ds = unsafeBitCast(0x6000006d74b0, to: WKWebsiteDataStore.self)
(lldb) po $ds
<WKWebsiteDataStore: 0x6000006d74b0>
rustyMagnet
  • 3,479
  • 1
  • 31
  • 41
1

I can confirm the same error, for Xcode beta4, and frame variable -L self

displays something, but seems worst:

: (SwiftCollectionViewSample.DetailViewController) self =

I will definitively filed a bug, Enrico

17819707 debugger prints error: use of unresolved identifier '$__lldb_injected_self'

shim
  • 9,289
  • 12
  • 69
  • 108
ing.conti
  • 145
  • 1
  • 2