Objective-C 依赖注入框架。不是 Guice 或 Spring 的端口。更好。更简单。
[[Class alloc]initWithSomeArgs]
。OCInject(Class)
和 OCInjectProtocol(protocol)
函数在各个地方注入依赖。[NSObject inject]
,相当于 OCInject(class)
。从 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