ObjectivePim

ObjectivePim is a small Dependency Injection Container for Objective-C based on Pimple's source

View project onGitHub

ObjectivePim

Build Status

ObjectivePim is a small Dependency Injection Container for Objective-C based on Pimple's source code (including this file :P).

 Installation

The supported way to get ObjectivePim is using CocoaPods.

Add ObjectivePim to your Podfile:

platform :ios, '6.1'

pod 'ObjectivePim'

Usage

Creating a container is a matter of instating the OPContainer class

#import <ObjectivePim/ObjectivePim.h>

OPContainer *container = OPContainer.new;

As many other dependency injection containers, ObjectivePim is able to manage two different kind of data: services and parameters.

Defining Parameters

Defining a parameter is as simple as using the ObjectivePim instance as a dictionary:

// define some parameters
container[@"foo"] = @"bar";
container[@"default_items"] = @5;

Defining Services

A service is an object that does something as part of a larger system. Examples of services: Database connection, templating engine, mailer. Almost any object could be a service.

Services are defined by blocks that return an instance of an object

// define some services
container[@"service"] = ^(void) {
    return Foo.new;
};

__block OPContainer *container = OPContainer.new;
container[@"other_service"] = ^(void) {
    return [[Bar alloc] initWithValue:container[@"value"]];
};

Notice that, in the second example, the block has access to the current container instance, allowing references to other services or parameters.

As objects are only created when you get them, the order of the definitions does not matter, and there is no performance penalty.

Using the defined services is also very easy

// get the service object
id service = container[@"service"];

Protecting Parameters

Because ObjectivePim sees blocks as service definitions, you need to wrap blocks with the protect: method to store them as parameter

container[@"random"] = [container protect:^(void){
    return @(arc4random());
}];

Modifying services after creation

In some cases you may want to modify a service definition after it has been defined. You can use the extend: method to define additional code to be run on your service just after it is created

container[@"afnetworking"] = ^(void) {
    NSURL *baseURL = [NSURL URLWithString:@"http://somehost.com"];

    return [[AFAppDotNetAPIClient alloc] 
             initWithBaseURL:baseURL];
};

[container extend:@"afnetworking" withCode:^(id service, OPContainer *container) {
    AFAppDotNetAPIClient *client = (AFAppDotNetAPIClient *)service;

    client.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
}];

The first argument is the name of the object, the second is a block that gets access to the object instance and the container.

Extending a Container

If you use the same libraries over and over, you might want to reuse some services from one project to the other; package your services into a provider by implementing OPServiceProviderProtocol:

@interface FooProvider : NSObject<OPServiceProviderProtocol>

@end 

@implementation FooProvider

- (NSString *)identifier
{
    return @"foo";
}

- (void)registerProvider:(OPContainer *)container
{
    // register some services and parameters
    // on container
}

@end

Then, the provider can be easily registered on a Container:

[container register:FooProvider.new];

FooProvider *foo = container[@"foo"];

Defining Factory Services

By default, each time you get a service, ObjectivePim returns the same instance of it. If you want a different instance to be returned for all calls, wrap your block with the factory: method

container[@"service"] = [container factory:^(OPContainer *container) {
    return [[Foo alloc] initWithValue:container[@"key_to_value"]];
}];