Crossing Contexts with StrangeIoC

This article is targeted at those already familiar with/using StrangeIoC, and describes a new feature set. If you’re interested in Strange (including the general topic of IoC/Dependency Injection in Unity3D) and how it might improve your development practices, check out the introductory article here:
http://thirdmotion.github.io/strangeioc/exec.html

StrangeIoC v0.6.0 adds some great features for working across and communicating between contexts. This article helps you learn how to use these features.

Introduction: Explaining Contexts

Let’s take a moment to understand what a context is and why you might want more than one. Think of a context as being like a ‘module’. Ideally a module can stand on its own without the rest of its application, but it has inputs and outputs so that it can integrate with other modules.

In Strange, each Context is defined by a set of mappings inside an extension of the Context Class (or more likely, an extension of MVCSContext). You could map your entire app inside a single, giant Context, but then the app becomes monolithic, i.e., it’s non-modular, harder to build, harder to debug, harder to integrate, harder to re-use. You can create separate contexts easily by creating multiple scenes, and attaching a ContextView and Context to those scenes.

Adding a Context

This particular feature hasn’t changed in v0.6.0; if you did it before, you know how to do it now. Just fire a Command with the following line in it:

Application.LoadLevelAdditive(“path-to-the-scene”);

You may find that a frame needs to elapse before you can do certain things, since the child Context needs to register.

Removing a Context

Removing a context has become slightly more automated in Strange v0.6.0. In fact, you probably already know how to do it…even if you don’t know that you know! In older versions it was necessary to explicitly remove the Context, and then destroy the ContextView GameObject. Something like:

Context.firstContext.RemoveContext(context);

GameObject.Destroy(contextView);

In the new version, we leverage the OnDestroy() method of MonoBehaviour to automate the process, so all you need to do is:

GameObject.Destroy(contextView);

The Context will automatically be removed for you.

Mapping Injections Across Contexts

Sometimes you want to share a mapping between contexts. For example, you might have a model — the holder for the game score or user data, say — which more than one context needs to know about. Strange’s old way of handling this straight-up sucked. You either had to dispatch the object you wanted to share using the crossContextDispatcher, then map it on arrival, or you had to call Context.GetComponent(), then re-map that “inherited” object in the child Context. Klunky, non-intuitive, high in polysaturated fat.

The new approach couldn’t be simpler. Observe. If you dare:

injectionBinder.Bind<ISpaceship>().To<Prometheus>().ToSingleton().CrossContext();

Boom. The mapping is now shared to other contexts. All the mappings you’re used to work this way: Singletons, value-mappings, named injections, factories.

Two quick caveats. First, while this mapping can appear anywhere in your app, we recommend that you default to placing it in your firstContext to avoid confusion. Second, note that if you re-map an identical key (or name/key pair) in a child context, the child mapping will override the cross-context mapping. This allows you to make exceptions where necessary.

Cross-Context Dispatching

For communicating between contexts (and presuming you’re not ready to switch to Signals, see below), Strange has the CrossContextDispatcher. While the dispatcher itself works just fine, it wasn’t right that you had to inject it into and dispatch it from various endpoints around your app. Implicit in nearly every piece of Strange is the idea that each Class know no more than strictly necessary; allowing a Mediator or Command to know that an event is intended to be consumed by another context violates this principle.

In delicious, new Strange v0.6.0, we fix this by having you bind your cross-context Events in the Context, using the new CrossContextBridge:

crossContextBridge.Bind(GameEvent.DESTROY_SHIP);

Having done this, GameEvent.DESTROY_SHIP will now be sent out across the CrossContextDispatcher and mappable by any other Context. The CrossContextBridge is shared by all Contexts, but as with cross-context injection bindings, we recommend that you default to entering your cross-context Event bindings in your firstContext’s mapBindings method.

Mapping Cross-Context Signals

In addition to these cross-context improvements, the big new feature in Strange v0.6.0 is Signals. Signals are a type-safe dispatch system. I’m not going to explain them here (there’s a section for this in the Big, Strange How-To), but if you’re starting to use them you might be wondering about mapping them across contexts.

Guess what? If you’ve read this far you already know how to do this. A signal is an object, no different from any other injected instance, so if you want to share one across contexts, simply map it cross-context:

injectionBinder.Bind<ShipDestroySignal>().ToSingleton().CrossContext();

The signal is now mappable to a Command or injectable inside any Context.

So those are the new cross-context features in v0.6.0. Hope they help you get more out of Strange. As always, please let me know what you’re doing with Strange, especially if you’re about to release something cool.

That’s me done. I’m off for some whisky.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s