I'm facing big issues when trying to print out Objective C properties in many situations when I'm almost certainly sure it SHOULD work.
Consider the following setup:
The view controller's property has strictly set class (Card *), but still, LLDB outputs an parsing error where subproperty cannot be found on object of type id.
Having an object property defined on a view controller (see points 5 & 6):
- stop at breakpoint inside the controller code (f.e. in -viewDidAppear: method)
- try to print out the property itself with
po _card(points 1 & 2) - try to print out its subproperty with
po _card.offlineURL(points 3 & 4) - an LLDB parsing error occurs
Printing out via [_card offlineURL] prints out proper object description as LLDB sends a message to Card object with no class check.
Definition of object property on the controller declares non-id class, though (point 5).
I'm expecting LLDB to print out the property object's subproperty description, NSString containing URL string in this case, but this annoying LLDB error occurs instead.
This is just a single example from many. Sometimes it affects direct property printout, numbers printing etc. These issues are way more frequent since integration of Swift began, being worse with every new version of Xcode since 6.2, including the latest 7.2.
This happens in my Objective C project in many situations, though sometimes it works fine in different cases.
Do you know about any work-arounds or fixes for this issue? I've already filed a report on Apple Bug Reporter, but this will certainly take time for Apple to even notice.
1 Answer 1
The most likely problem given the info in your question is that we don't actually have debug information for _card.
The lldb command:
(lldb) image lookup -t Card
will tell you whether lldb had debug information for Card available to it. If this doesn't find anything, then maybe some part of your project isn't getting built with debug info. If the command does find some correct definition of Card, then it must be that the debug info for the _card ivar is not getting hooked up to this type correctly.
If there is a definition of Card, then the workaround:
(lldb) po ((Card *) _card).offLineURL
is available.
For future reference, there are two other bits of behavior that are probably complicating your attempt to figure out what is going on here:
1) (w.r.t. picture 3) The Xcode IDE uses its built-in indexer for auto completion in the debug window as well as the Source Code editor. But the debugger runs off debug information, since we need to be able to debug things that aren't built in Xcode. So the fact that auto-completion can find a name in an expression doesn't tell you anything about what lldb will do.
2) (w.r.t. picture 2) po force-casts the expression you are trying to "po" to an ObjC object (i.e. "id") and then calls its description method. The description method of an ObjC object that doesn't override description prints the type name and the address. So lldb didn't need to know the type of the _card ivar to get the output you saw. We only start to need types when the expression is more complex and involves accesses to ivars or properties of an ObjC object in the expression.
Note also, by default if you do:
(lldb) print _card
lldb will evaluate the expression "_card", find it resolves to a pointer of at least type id, then follow that pointer's isa pointer into the ObjC runtime to figure out what the dynamic type is. So it is likely to print Card * in this case.
But the expression parser hasn't yet been taught to resolve the dynamic type of sub-expressions within the expression parser in mid-parse. That would actually be quite a trick... So if it doesn't know the full type of _card, then:
(lldb) print _card.offlineURL
isn't going to work, since id does indeed not have a property of that name.
You can work around this by doing:
(lldb) print _card
0ドル = (Card *) 0x12345678
Then:
(lldb) print 0ドル.offlineURL
since the result variable captures the full dynamic type information, that will also be available in subsequent expressions.
7 Comments
image lookup command shows me proper info about declaration in a header file along with all the properties listed. Casting a property is quite obvious, but very annoying when you need to fast-watch variables or method results quickly, which you usually need when debugging.po [SessionManager defaultSession] prints out proper description of a singleton object, calling po [SessionManager defaultSession].userInfo throws no known method '+defaultSession'; cast the message send to the method's return type – how cannot it find the method, when it's been called on the previous line with no issues? Trickily, po @(124).integerValue or po @"Hello World!".length works with no issues, though I don't find it in any way less complicated than evaluating over own classes above.p self.view.frame ends with property 'frame' not found on object of type 'UIView *' – that's totally awkward. On the other hand, p _card.offlineURL prints proper variable value, what's the difference in parsing in po then? I would somehow bet NSString * has its -description implemented.
e @import UIKit.UIViewControllerstuff, if I'd have a hierarchy of objects and want to print its sub-sub-sub-properties, it would fail the same way (and it happens, f.e. in singleton managers not working with any UIKit stuff, just pure Foundation code), this specific example is only another I've just found.@importtrick. I don't know why it seems to work on non-UI classes, but for me it does. Sorry it didn't help you.