Skip to content

Latest commit

 

History

History
executable file
·
58 lines (45 loc) · 2.39 KB

File metadata and controls

executable file
·
58 lines (45 loc) · 2.39 KB

CWPack / Goodies / ObjC / Technique

We have choosen to represent objects as arrays. To be able to differentiate objects from normal arrays we have put an object marker as the first slot of the array. The object marker is an EXT item with type 127. The second array slot is kept by the class name. The rest of the array slots are kept by the objects attributes.

User objects

We have an example:

@interface MyClass: NSObject <CWPackable>
@property    int     level;
@property    MyClass *link;
- (instancetype) initWithLevel:(int)level link:(MyClass*)link;
@end

When packed into a MessagePack stream it may look like:

[(127,<00>) "MyClass" 37 NULL]

This was the simple example where the link was nil. But look at this code fragment:

MyClass *a = [MyClass.alloc initWithLevel:10 link:nil];
MyClass *b = [MyClass.alloc initWithLevel:20 link:a];
a.link = b; 
[myContext packObject:a];

To not fall into eternal recursion we need to break the circular reference in some way. We do it by giving the objects labels (set useLabel = YES on pack context). The labels are just consecutive numbers starting at 1. We store the label in the objects markers payload. Let´s start packing:

[(127,<01>)			// object a got the label 1, we note that in a table
[(127,<01>) "MyClass" 10 [(127,<02>) "MyClass" 20 

Now it is time to insert object a again. But this time we have the object in our table and instead of packing the object we just pack a reference to it. A reference is an array with a single slot that is the object marker. The final result becomes:

[(127,<01>) "MyClass" 10 [(127,<02>) "MyClass" 20 [(127,<01>)]]]

The cwpack dump utility "knows" object markers and prints the above message as:

1->MyClass(10 2->MyClass(20 ->1))

MessagePack items

It is not just user objects that can contain circular references. Take this example:

NSMutableArray *a = NSMutableArray.new;
[a addObject:a];
[myContext packObject:a];

Obviously we need a way to label MessagePack objects also. To that point we divide the MessagePack items in two cathegories: references and values. Arrays and maps are references and all other items are values. For references we do as for user objects, but instead of a class-name in the second slot we put the MessagePack object. In this case, there are just 2 slots. So the packing above becomes:

[(127,<01>) [[(127,<01>)]]]

Or prettyprinted: 1->[->1]