Skip to content
Jon Gilkison edited this page Nov 12, 2012 · 1 revision

ModelKit has a global graph that stores all models you create, allowing your application access to all instances regardless of where in your code it's accessing it from. This provides a variety of benefits:

  • No duplication of object instances
  • You can persist and load graphs to/from file
  • You don't have to worry about managing memory as it relates to your models
  • Global access to all model instances

Normally, you will never need to worry about graphs, but will need to follow some simple guidelines:

  • Model instances you create should be auto released

Ok, 1 simple guideline. So that's easy, right?

Let's look at some examples:

	-(void)someAction:(id)sender
	{
    	CSMPAuthor *author=[[CSMPAuthor alloc] init];
    	// do some stuff.
	}

In this example, we just leaked an object because we didn't autorelease it. This is the proper way:

	-(void)someAction:(id)sender
	{
    	CSMPAuthor *author=[[[CSMPAuthor alloc] init] autorelease];
    	// do some stuff.
	}

You might think that because we're autoreleasing the object that it will be released once we exit this method. This is not the case as the model graph retains all models created. So, in a way, this model could be considered leaked if it is not your intention to ever use it again.

If we wanted to release the model the proper way to write this would be:

	-(void)someAction:(id)sender
	{
    	CSMPAuthor *author=[[[CSMPAuthor alloc] init] autorelease];
    	// do some stuff.
    	[author removeFromGraph];
	}

Calling removeFromGraph insures that the model is removed from the graph.

###Fetching Models

You can fetch a model at a later stage by requesting it from the graph again. You can do this using the model's modelId or by its objectId.

To do this "manually" using the graph:

	-(void)createModelAction:(id)sender
	{
    	CSMPAuthor *author=[CSMPAuthor instanceWithObjectId:@"0001"]; // this is already auto-released
    	author.name="Jon Gilkison";
    	author.email="jon@interfacelab.com";
	}
	
	-(void)fetchModelAction:(id)sender
	{
		CSMPAuthor *author=(CSMPAuthor *)[[MKitModelGraph current] modelForObjectId:@"0001" andClass:[CSMPAuthor class]];
	}

Now, you're never going to do it this way. The better way is:

	-(void)someAction:(id)sender
	{
    	CSMPAuthor *author=[CSMPAuthor instanceWithObjectId:@"0001"]; // this is already auto-released
    	author.name="Jon Gilkison";
    	author.email="jon@interfacelab.com";
	}
	
	-(void)someOtherAction:(id)sender
	{
		CSMPAuthor *author=[CSMPAuthor instanceWithObjectId:@"0001"];
		if ([author.name isEqualToString:@"Jon Gilkison"])
			NSLog(@"Same instance.");
	}

The instanceWithObjectId and instanceWithModelId class methods always first check the graph for an existing model with matching id and return that instance instead of creating a new one. If it can't find one, it'll create a new instance, add it to the graph and then return it.

###Removing a Model From The Graph Removing a model from a graph is this simple:

    CSMPAuthor *author=[CSMPAuthor instanceWithObjectId:@"0001"];
    [author removeFromGraph];

You'll need to be careful here because if any object has this object as a property, because it's a weak reference, you'll crash your application.

###Multiple Graphs There might be conditions where you want to create a temporary graph, perhaps to load a bunch of temporary objects for processing.

	// Push a new graph onto the graph stack
    [MKitModelGraph push]; 
    
    // Load up a bunch of objects…
    for(int i=0; i<100; i++)
    	[CSMPAuthor instanceWithObjectId:[NSString stringWithFormat:@"%d",i]];
    	
    // Do our processing
    
    // Dump the graph and it's associated objects
    [MKitModelGraph pop];

In this example, we pushed a new graph onto the graph stack, created a bunch of objects and then popped the graph off.

In a more complicated example, we can push a new graph onto a stack, retain a reference to it, pop it off and then push it onto the stack again later:

	MKitModelGraph *newGraph=[[MKitModelGraph push] retain];
	    
    // Load up a bunch of objects…
    for(int i=0; i<100; i++)
    	[CSMPAuthor instanceWithObjectId:[NSString stringWithFormat:@"%d",i]];
    	
    // Do our processing
    
    // Dump the graph and it's associated objects
    [MKitModelGraph pop];
    
    // Do some other stuff
    
    // Restore our graph:
    [newGraph activate];
    
    // Create some more objects ...
    for(int i=0; i<100; i++)
    	[CSMPAuthor instanceWithObjectId:[NSString stringWithFormat:@"%d",i]];
    	
    // Deactivate the graph
    [newGraph deactivate];
    
    // Release it to destroy it
    [newGraph release];

It's important to know that there can only be one graph active at a time. If a background thread is creating objects at the same time as the above code is running, those objects created in the background will exist in the current thread. This is a big TODO.

###Persisting Graphs You can store an entire graph to file, as well as restore it at a later time:

	[[MKitModelGraph current] writeToFile:@"/tmp/persisted.plist" error:nil];

You can then restore it:

	[[MKitModelGraph current] loadFromFile:@"/tmp/persisted.plist" error:nil];

This makes it super simple to save your entire object graph on application exit and restore it the exact same point when you launch the application again.

###Clearing Graphs You can reset the entire graph system:

	[MKitModelGraph clearAllGraphs];

Or, just clear one of them:

	[[MKitModelGraph current] clear];

This will remove all objects from the graph, releasing them.

###No Graph Models There will definitely be times when you don't want your model to ever be added to a graph. This is simple to achieve by adding the MKitNoGraph protocol to your model:

    #import "MKitModel.h"
    
    @interface CSMPAuthor : MKitModel<MKitNoGraph>
    
    @property (copy, nonatomic) NSString *name;
    @property (copy, nonatomic) NSString *email;
    @property (retain, nonatomic) NSDate *birthday;
    @property (assign, nonatomic) NSInteger age;
    @property (assign, nonatomic) BOOL displayEmail;
    @property (copy, nonatomic) NSString *avatarURL;
    
    @end

Any instances of this object will not be added to the graph ever, unless you do so manually:

	CSMPAuthor *author=[CSMPAuthor instanceWithObjectId:@"001"];
	[author addToGraph];

###Graph Information All graphs have two properties that tell you information about it:

  • graphSize The size of the graph in bytes. This is a rough guesstimate and should not be relied on as fact.
  • graphCount The number of objects currently stored in the graph

You can use it:

	NSLog(@"Graph Size: %d",[MKModelGraph current].graphSize);
	NSLog(@"Graph Count: %d",[MKModelGraph current].graphCount);
Clone this wiki locally