If you’re working on an app that uses Core Data, it’s inevitable that you’ll end up in the debugger and need to dig around in the object graph. You’ll also quickly realize that Core Data’s -description
of an object isn’t terribly helpful:
(lldb) po myListObj (List *) $19 = 0x08054ac0 <List: 0x8054ac0> (entity: List; id: 0x8074280 <x-coredata://29B10357-0723-4950-9EB6-E6D7AD6269B9/List/p175> ; data: <fault>)
Core Data’s documentation is excellent, but surprisingly doesn’t cover some of the tricks you can use to examine managed objects in the debugger.
The first trick is to fire a fault on the object using -willAccessValueForKey
. After that, you can see what’s really there:
(lldb) po [myListObj willAccessValueForKey:nil] (id) $20 = 0x08054ac0 <List: 0x8054ac0> (entity: List; id: 0x8074280 <x-coredata://29B10357-0723-4950-9EB6-E6D7AD6269B9/List/p175> ; data: { containerId = "8E4652D3-5516-4186-B1C9-DDBE41E108CF"; createdAt = "2009-10-08 15:17:53 +0000"; itemContainers = "<relationship fault: 0x8020850 'itemContainers'>"; })
You might also be surprised when you try to access one of the properties of the object:
(lldb) po myListObj.containerId error: property 'containerId' not found on object of type 'List *' error: 1 errors parsing expression
Remember that these properties are defined as @dynamic
and there’s a lot of work done by Core Data at runtime to provide the implementation. The solution here is to use the KVC accessor -valueForKey:
to get the object’s value:
(lldb) po [myListObj valueForKey:@"containerId"] (id) $26 = 0x08069b60 8E4652D3-5516-4186-B1C9-DDBE41E108CF
Often, you’ll want to examine the relationships between objects. As you can see in the output above, the attribute itemContainers
, which is a to-many relationship, is a fault. To fire the fault, get all the objects from the set:
(lldb) po [[myListObj valueForKey:@"itemContainers"] allObjects] (id) $23 = 0x0d0667b0 <__NSArrayI 0xd0667b0>( <Container: 0x807a180> (entity: Container; id: 0x801bc50 <x-coredata://29B10357-0723-4950-9EB6-E6D7AD6269B9/Container/p1> ; data: { containerId = TestContainer; items = "<relationship fault: 0x805b100 'items'>"; state = "(...not nil..)"; type = 4; }) )
Finally, you may be using Transformable attribute types. The state attribute above is an example. If you’d like more information than (...not nil...)
, use the KVC getter and you’ll see that it’s an empty NSDictionary
:
(lldb) po [[[[myListObj valueForKey:@"itemContainers"] allObjects] lastObject] valueForKey:@"state"] (id) $29 = 0x0807dd30 { } (lldb) po [[[[[myListObj valueForKey:@"itemContainers"] allObjects] lastObject] valueForKey:@"state"] class] (id) $30 = 0x01978e0c __NSCFDictionary
It’s taken me months to learn these tricks, so hopefully this short essay helps you come up to speed more quickly than I did!