I have two entities, Chain
and Step
. Chain
has an attribute steps
, which may be a multidimensional array of Step
entities, for example:
[
step,
step,
step,
[
step,
step
],
step
]
Each Step
object has a content
property that is a string.
If I were using a relational database, I'd simply store that array as JSON, with each step
being the step_id
of a particular step.
How would I achieve something similar in Core Data? I gather that I would need to make the Step
class conform to the NSCoding Protocol, but what would that look like? How would I make it only store the equivalent of its id
, i.e. a reference to itself, in the final value of Chain.steps?
EDIT
A comment below suggests that I include a one-to-many relationship (let's call it nextStep
) between Step
and other Steps
. I would then use this relationship to go from one step to the next in a Chain
, and thus the Chain
entity would only need to contain the first Step
in the sequence. The problem with this is that a Step
may belong to more than one Chain
, and thus it may not always have the same nextStep
value.
Unity cannot serialize multidimensional arrays, but that does not mean it is a lost cause, because Unity does give you the power to help it along. I have not looked into (or had the need for) serialization of staggered arrays, so this is out of scope for now.
I'm going to show the approach that I took that works for me. It's simple, and easy to implement. TL;DR When you want to persist data in a multidimensional array, wrap the stuff in a package, and put the packages in a list before serialization, and reconstruct your array from this list of packages after deserialization.
I just made a general remark. jagged arrays are in fact serializable by Unity because it's just 'layers' of one-dimensional arrays, and those are serializable. Click to expand... Well, I'm not sure about that.
Some serialization frameworks don't allow such cycles. For example, Json.NET will throw the following exception if a cycle is found. Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'Blog' with type 'MyApplication.Models.Blog'.
I would like to discourage you from serializing and deserializing arrays that include Core Data objects. It is possible, you could transform your arrays to hold the URIRepresentation
of the object IDs of your steps, but what happens if you delete a step from the database? Your serialized arrays remain tainted with old objects.
Here is my proposal.
https://github.com/LeoNatan/ChainStepsExample
My model is set like this:
Link
is an abstract entity.
For ease of use, I have defined the following protocol:
@protocol Link <NSObject>
//This is to make chain traversal easy - all links are guaranteed to have "steps".
- (NSOrderedSet*)steps;
@end
And for creation, I added the following convenience factory methods:
@interface Link : NSManagedObject <Link>
+ (id<Link>)linkWithStepsArray:(NSArray*)stepsArray inContext:(NSManagedObjectContext*)context;
+ (id<Link>)linkWithStepsOrderedSet:(NSOrderedSet*)stepsOrderedSet inContext:(NSManagedObjectContext*)context;
+ (id<Link>)linkWithStep:(Step*)step inContext:(NSManagedObjectContext*)context;
@end
Now, creation of a chain and traversal are very easy.
Step* step1 = [Step newObjectInContext:context];
step1.content = @"Wake up";
Step* step2_1 = [Step newObjectInContext:context];
step2_1.content = @"Go to school";
Step* step2_2 = [Step newObjectInContext:context];
step2_2.content = @"Learn new things";
Step* step3 = [Step newObjectInContext:context];
step3.content = @"Go to sleep";
NSOrderedSet* links = [NSOrderedSet orderedSetWithObjects:[Link linkWithStep:step1 inContext:context], [Link linkWithStepsArray:@[step2_1, step2_2] inContext:context], [Link linkWithStep:step3 inContext:context], nil];
[chain setLinks:links];
And finally traversal:
for(Chain* chain in chains)
{
NSLog(@"<chain %@>", chain.name);
for(id<Link> link in chain.links)
{
NSLog(@"\t<step>");
for(Step* step in link.steps)
{
NSLog(@"\t\t%@", step.content);
}
NSLog(@"\t</step>");
}
NSLog(@"</chain>\n\n");
}
This allows you a manageable object graph, which will rebuild itself automatically when a task is removed.
This is a simple example. It only solves one level deep. You could have a relationship between SingleStepLink
or MultiStepLink
and Link
(instead of Step
) to have an infinite depth, with leafs having the final relationship with Step
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With