Skip to content
This repository

Dependency Injection for iOS / ObjC

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 APServiceBox.xcodeproj
Octocat-spinner-32 APServiceBox
Octocat-spinner-32 APServiceBoxTests
Octocat-spinner-32 .gitignore
Octocat-spinner-32 APServiceBox.podspec
Octocat-spinner-32 README.md
README.md

Stories in Ready

APServiceBox

How to use

Quick & easy way: drag the two files "APServiceBox.m" and "APServiceBox.h" into your project.

The nice way: you tell me...

Use it when...

Use this box when you have services or objects that must be available throughout the application. For example, if all your *ViewControllers need to report analytics, or depend on a single data source.

Usage example

The first thing you should do is register your services and other dependencies into the default service box.

AnalyticsManager *analyticsManager = [[AnalyticsManager alloc] init];
[[APServiceBox defaultBox] registerDependency:analyticsManager as:@"analyticsManager"];

// Or you can create your own box
APServiceBox *myBox = [[APServiceBox alloc] init];

Self-injection The easiest way to inject dependencies is to call the fillWithDependencies method in the init of an object. This will use the default service box to fill the current object.

@interface MyViewController
@property (strong, nonatomic) AnalyticsService *analyticsService;
@end


#import "NSObject+APServiceBox.h"
@implementation MyViewController

- (id)init {
    self = [super init];

    if (self) {
        // This will ask the [APServiceBox defaultBox] to provide available dependencies
        [self fillWithDependencies];
    }

    return self;
}

@end

Injection conditions

There are two conditions for a dependency to be injected:

  1. the @property name corresponds to the name given when registering the service
  2. the @property type matches the registered service, that is (one of the following):
    • service.class == @property.class
    • [service isKindOfClass:@property.class]
    • [service.class conformsToProtocol:@property.protocol]

Thus, the following two forms of properties are valid:

// Will match any AnalyticsService (or subclass) object
@property (...) AnalyticsService *analyticsService;

// Will match any object that conforms to <AnalyticsService> protocol
@property (...) id<AnalyticsService> *analyticsService;

Inject from outside the class

// Create the box
APServiceBox *box = [APServiceBox defaultBox];

// Register some services in it, here a fictive AnalyticsService object
[box registerDependency:analyticsService as:@"analyticsService"];

// Use the box to inject dependencies into object's properties
// The dependencies will be injected based on names and classes/protocols
[box fill:myViewController];

// For example, if myViewController has a property defined as follow:
@property (...) AnalyticsService *analyticsService;
// then the analyticsService from above will be injected.

Inject the box itself

If you need to inject the box itself into one of the objects (typically a UIViewController that will create other UIViewControllers), you can simply add a @property of type APServiceBox and named "serviceBox".

@property (strong, nonatomic) APServiceBox *serviceBox;

Cross-dependency injection

When you call fill: for the first time, APServiceBox will scan and fill each of the registered dependencies. This allows the following scenario:

@interface StorageManager

@end
@interface PreferenceManager

@property (strong, nonatomic) StorageManager *storageManager;

@end
APServiceBox *box = [[APServiceBox alloc] init];
[box registerDependency:preferenceManager as:@"preferenceManager"];
[box registerDependency:storageManager as:@"storageManager"];

// And if you invoke...
[box fill:myObject];

// ...then the following is true:
preferenceManager.storageManager == storageManager;

Need more?

If you need more insights on how this works, have a look at the test file: it's short and clear! Or contact me ;)

Contact me

Name's Antoine.

License & Author

Feel free to use this for commercial works, and I'd be glad to hear from you, or why not see my name in a "thanks" section :)

This code is available under the MIT license.

Hope you like this little utility. Have fun!

Something went wrong with that request. Please try again.