Search code examples
objective-cdependency-injectiontyphoon

Lazily instantiate dependencies using DI in iOS (Typhoon & Objection)


I am a huge fan of dependency injection pattern but I am a little sceptical when it comes to following this pattern in mobile development and the main reason being memory allocation. I will briefly explain what my concern is:

I am using DI in my Objective-C based iOS project. I have used both Objection and Typhoon but could not find a way to lazily instantiate the dependencies (not talking specifically about Singletons). I get my dependencies injected even if the use case flow of the app does not require the object to be allocated. As soon as I call injectDependencies: method (Objection) or plist Integration (Typhoon) all the dependencies are injected. Although Objection site mentions it lazily loads everything but I didn't see a proof of that. Is there a way to lazy load the dependencies using these frameworks? For example, I want something like this:

@property (nonatomic) MyClass *classObject;

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Check at this point that classObject should be nil

    id str = classObject.myString;

    // As soon as the getter is called, the property is first instantiated and then returned a value.
}

Is DI meant to be this way? If yes then doesn't this pattern defies the memory allocation thumb rule for mobile (allocate only when you need it)?


Solution

  • Typhoon founder here.

    Dependency Injection on Server Side Projects

    When we use Dependency Injection with server-side frameworks, the default scope is singleton. This makes sense, given that the server could be expected to serve any use-case at a given point in time.

    Dependency Injection on Mobile And Desktop

    In iOS we may have some background (singleton) components, however we're typically focusing on one use case at a time. Therefore, Typhoon introduces the unique TyphoonScopeObjectGraph as the default among its scopes.

    With TyphoonScopeObjectGraph means that the relationship between dependencies are described, a Typhoon will create a shared instance only while the object graph is being solved. This means you can wire-up a complex object graph using circular dependencies (delegate pattern) and so forth. Typhoon then hands this entire object graph to whatever will be using it, and releases ownership.

    Normal Objective-C runtime rules apply from here - if the controller or whatever is using the built object-graph has a strong property, then the graph will be retained in memory as long as that view controller is.

    In this way we can proceed from one object graph (use-case) to another, while preserving memory on resource constrained devices.

    Other Scopes

    Typhoon also includes the following additional scopes besides the default:

    • TyphoonScopeSingleton - retained by the DI container. Use for background daemons and so forth.
    • TyphoonScopeLazySingleton - like a regular singleton, but instantiation is delayed until the first time it is used. (I believe Objection singletons work like this).
    • TyphoonScopeWeakSingleton - instantiated and shared as long as at least one object is retaining it, then destroyed. Will be re-instantiated the next time it is requested again.
    • TyphoonScopePrototype - always creates a new instance, even during a single solve cycle.

    Proceeding from One Object Graph to Another:

    A typhoon built story board can load another object-graph, such as another view controller to proceed to a new use-case 'on-demand'. To do this we Typhoon as a factory class, and inject the assembly itself, optionally. We can then ask Typhoon to build an instance of the required class. If you wish you can back your assembly with a protocol, so that your class is not coupled directly to Typhoon.