OCInject 0.3.0

OCInject 0.3.0

测试已测试
语言语言 Obj-CObjective C
许可协议 自定义
发布最新发布2014年12月

未指派 维护。



OCInject 0.3.0

  • 作者
  • Ivan Korobkov

Objective-C 依赖注入框架。不是 Guice 或 Spring 的端口。更好。更简单。

关键特性

  • 快速且小巧。
  • 非常容易使用。
  • 不会剥夺您的 [[Class alloc]initWithSomeArgs]
  • 不会管理应用程序对象图。
  • 通过 OCInject(Class)OCInjectProtocol(protocol) 函数在各个地方注入依赖。
  • 提供可选分类方法 [NSObject inject],相当于 OCInject(class)
  • 由于 运行时绑定,几乎无需配置。
  • 透明地集成到测试/模拟中。
  • 线程安全。
  • 支持 iOS 6+ 和 OSX 10.8+ with ARC。

用法

从 CocoaPods 安装

pod 'OCInject'

代码

#import "OCInject.h"

// Given some dependencies.
@interface Cache : NSObject
@end

@interface Servcie : NSObject
@end

@protocol Validator
@end


// Configure a shared injector in your app delegate.
// Typically, almost zero configuration is required because of automatic runtime bindings.
@implementation MyAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [OCInjector configure:^(OCInjectBinder *binder) {
        [binder installModule:[[MyModule alloc] init]];     // Include bindings from a module.

        // Add some bindings.
        [binder bindClass:UIApplication.class toInstance:[UIApplication sharedApplication]];
        [binder bindClass:NSNotificationCenter.class toInstance:[NSNotificationCenter defaultCenter]];
        [binder bindProtocol:@protocol(Validator) toConstructor:^() {
            return [[MyValidator alloc] init];
        }]
    }];

    return YES;
}
@end


// Inject the dependencies wherever you need.
@implementation MyViewController {
    Cache *_cache;
    Service *_service;
    UIApplication *_app;
}

// In constructors.
- (instancetype)initWithCoder:(id)decoder {     // Invoked by a storyboard.
    if (self = [super initWithCoder:decoder]) {
        _app = [UIApplication inject];
        _cache = [Cache inject];
        _service = OCInject(Service.class);
    }

    return self;
}

// In methods and fuctions.
- (void)myMethod {
    id<Validator> validator = OCInjectProtocol(@protocol(Validator));
}
@end

测试

OCInject 在测试中非常容易使用。在 setUp 中配置一个新的注入器与一些测试/模拟绑定,并在可选的 tearDown 中清除它。

@interface MyViewControllerTests : XCTestCase
@end

@implementation MyViewControllerTests
- (void)setUp {
    // Using OCMockito for mocks.

    [OCInjector clearAndConfigure:^(OCInjectBinder *binder) {
        [binder bindClass:Cache.class toInstance:mock(Cache.class)];
        [binder bindProtocol:@protocol(Validator) toInstance:mockProtocol(@protocol(Validator))];
    }];
}

- (void)tearDown {
    // This is absolutelly optional.
    [OCInjector clear];
}
@end

线程安全

配置后,注入器是线程安全的,可以被多个线程使用。

绑定

OCInject 支持几种绑定类型,用于指定实例是如何创建的

  • 实例绑定,总是返回相同的实例

    [OCInjector configure:^(OCInjectorBinder *binder) {
        [binder bindClass:NSNumber.class toInstance:@(123)];
    }];
  • 构造器绑定,在第一次注入时创建单例。

    [OCInjector configure:^(OCInjectorBinder *binder) {
        [binder bindClass:Cache.class toConstructor:^() {
            // Executed only once on first injection.
            return [[Cache alloc] initWithArg:123];
        }];
    }];
  • 供应器绑定,在每次注入时执行。

    [OCInjector configure:^(OCInjectorBinder *binder) {
        [binder bindClass:CurrentUser.class toProvider:^() {
            // Executed on every injection.
            return [CurrentUser randomUser];
        }];
    }]
  • 运行时绑定,当没有显式绑定时,自动为类创建。类作为 [[Class alloc] init] 单例创建。以下不需要为 PriceFormatter 提供绑定。

      @interface PriceFormatter : NSObject
      - (instancetype)init;
      @end
    
      @implementation ProductsController  // UITableViewController subclass
      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
          PriceFormatter *formatter = [PriceFormatter inject];
          // create and return a product cell.
      }
      @end

模块

模块是可选的,因为您可以使用单个代码块配置注入器。但是,有时在需要将一些绑定分组在一起时,模块很有用。

@interface MyModule : OCInjectModule
@end

@implementation MyModule
- (void)configure:(OCInjectBinder *)binder {
    // Module bindings.
    [binder bindProtocol:@protocol(MyService) toConstructor:^() {
        return [[MyServiceClient alloc] initWithUrl:@"http://example.com/"];
    }]
}
@end

在配置期间将模块安装到绑定器上

[OCInject configure:^(OCInjectBinder *binder) {
    [binder installModule: [[MyModule alloc] init]];
    // Other bindings.
}

为什么不使用作用域?

我已经用了很多年 Guice 和 Spring,我不喜欢它们的范围(这个概念)。此外,一些作用域(例如,请求范围或会话范围)是很脆弱的,引入了高耦合,并且很难测试。OCInject 使用自定义构造器和供应器,这比作用域更加灵活。需要作用域?写一个供应器。

稳定性

OCInject 稳定且经过充分的测试。它是专门针对 Objective-C 定制的、成熟的依赖注入框架 python-inject 的移植。如果您发现任何错误,请报告它

链接

许可证

Apache License 2.0