Coder Social home page Coder Social logo

snapking / blindside Goto Github PK

View Code? Open in Web Editor NEW

This project forked from jbsf/blindside

0.0 1.0 0.0 323 KB

Blindside provides dependency injection capabilities for Objective-C on iOS and OS X

License: MIT License

Objective-C 62.93% Ruby 6.09% C 0.30% Objective-C++ 28.36% Swift 2.32%

blindside's Introduction

Blindside: dependency injection for Objective-C

Carthage compatible

Why should I use this?

Blindside helps you write clean code. You can keep your objects loosely coupled and ignorant of the world outside. Your objects can create other objects without needing to know about the other objects' dependencies.

What's with the name?

It's a play on the idea that objects should be blind to the origin of their dependencies. Mostly, however, it's fun to name classes "BSInjector", "BSProvider", etc.

What, are we Java?

Sadly, yes. Objective-C and Java are identical with respect to the object-level dependency management offered by the language: basically none. Global variables, "sharedInstance" singletons, and pass-through parameters are the common patterns used to access dependencies. None are good options.

Guice brought elegant object dependency management to Java, obviating the need for static data, and fulfilling the promise of true OO programming. Blindside seeks to do the same for Objective-C.

What features does it have?

  • Injecting dependencies of UIViewController subclasses, including master/detail view controllers
  • "Constructor injection" via initializers
  • "Setter injection" via properties
  • Injection of third-party classes using categories
  • Binding to instances, blocks, Providers, or classes
  • Scoped bindings, including Singletons
  • Support for creation-time parameters not defined in bindings.

Status

Blindside is alpha software. There's no documentation aside from this readme. My focus is now on building out the documentation, along with examples. I'm using it on my current iOS project and it's working nicely. I've published it as-is to see if it stirs any interest. If you've come across this readme and have some questions, or would like to learn more on how to use Blindside, please get in touch.

How does it work?

You describe your object's dependencies, define bindings to fill those dependencies, then ask the BSInjector to create your objects. Here's a "Hello, World" example:

/**
 * Our view controller. It needs to be created with an api instance.
 */
@interface MyViewController : UIViewController
- (id)initWithApi:(id<MyApi>)api;
@end

@implementation MyViewController

/**
 * Describing MyViewController's dependencies. We want instances initialized using initWithApi:, which takes one arg.
 */
+ (BSInitializer *)bsInitializer {
		return [BSInitializer initializerWithClass:self 
		                                  selector:@selector(initWithApi:) 
		                              argumentKeys:@"myApi", nil];
}

...

@end


@interface MyBlindsideModule : NSObject<BSModule>
@end

@implementation MyBlindsideModule

/**
 * Creating a binding for our MyApi dependency.
 */
- (void)configure:(id<BSBinder>) binder {
		id<MyApi> apiInstance = [[MyApiImpl alloc] initWithEndpoint:@"http://api.mycompany.com"];
		[binder bind:@"myApi" toInstance:apiInstance];
}
@end


@implementation AppDelegate
- (void)applicationDidFinishLaunching {
		...
		// Creating an injector configured with our BSModule. Asking the injector for an instance of our ViewController.
		MyBlindsideModule *module = [[MyBlindsideModule alloc] init];
		id<BSInjector> injector = [Blindside injectorWithModule:module];
		UIViewController *rootViewController = [injector getInstance:[MyViewController class]];
		
		...
}
@end

Obviously you don't need a framework to accomplish a task this trivial. Blindside really helps when MyViewController creates another view controller, which creates another, which has additional dependencies, and so on.

Describing dependencies

Blindside provides dependencies to objects in two ways: via an initializer (e.g. initWithDelegate:), or using properties. You can mix and match the two.

Blindside relies on two class methods for describing dependencies. These methods are added to NSObject in the NSObject+Blindside category, and are meant to be overridden by classes injected with Blindside. The methods are:

  • (BSInitializer *)bsInitializer;
  • (BSPropertySet *)bsProperties;

bsInitializer describes the initialization method to be used when creating instances of a class, including the initializer's selector and arguments. Blindside can use a class' BSInitializer to create instances of the class, with dependencies injected.

bsProperties describes the properties to be injected into already-created objects.

Here's an example implementation of the two methods for a class named House. The House class takes an Address as an initializer arg, and has a property of type UIColor.

@implementation House

+ (BSInitializer *)bsInitializer {
		SEL selector = @selector(initWithAddress:)
		return [BSInitializer initializerWithClass:self selector:selector argumentKeys:[Address class]];
}

+ (BSPropertySet *)bsProperties {
		BSPropertySet *propertySet = [BSPropertySet propertySetWithClass:self propertyNames:@"color", nil];
		[propertySet bindProperty:@"color" toKey:@"myHouseColor"];
		return propertySet;
}
 ...

Awaking from injection

When working with property injection, it is occationally desirable to have a hook that can be used to finish setting up an object after all dependencies have been injected. Blindside provides a mechanism for this:

@implementation House
- (void)bsAwakeFromPropertyInjection {
	// Finalize instantiation
}
 ...

Note that the use of this method is discouraged because it increases the coupling between your code and Blindside. First look for other appropriate lifecycle methods on your object (e.g. -viewDidLoad for a view controller) that could be used to perform this kind of work.

Swift

You can also use Blindside in Swift. First, add #import <Blindside/Blindside.h> to your Swift's bridging header file to expose the framework to your Swift code.

Create an injector as you would in Objective-C:

let module = MyBlindsideModule()
let injector = Blindside.injectorWithModule(module)

To instantiate your controller with no arguments:

let controller = injector.getInstance(MyViewController.self)

To pass dynamic arguments (those marked with BS_DYNAMIC) to your controller, use the newly exposed -getInstance:withArgArray: method.

let controller = injector.getInstance(MyViewController.self, withArgArray: [BSNull(), "arg"])

Describe your class dependencies like this:

class House : NSObject {
    class override func bsInitializer() -> BSInitializer {
        // `selector` requires the Objective-C method name of your initializer
        return BSInitializer(withClass: self, selector: "initWithAddress:", argumentKeysArray: [Address.self])
    }

    class override func bsProperties() -> BSPropertySet {
        let propertySet = BSPropertySet(withClass: self, propertyNamesArray: ["garage"])
        propertySet.bindProperty("color", toKey: "myHouseColor")
        return propertySet
    }
}

Note that Blindside is only able to create and inject NSObject-derived classes.

Author

Copyright (c) 2012 JB Steadman. This software is licensed under the MIT License.

blindside's People

Contributors

akitchen avatar christian-smith avatar jbsf avatar jeffh avatar joemasilotti avatar odlp avatar wileykestner avatar xtreme-steven-wu avatar zacclark avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.