Objection 是一个面向 MacOS X 和 iOS 的 Objective-C 的轻量级依赖注入框架。对于那些使用过 Guice 的人来说,Objection 会感觉熟悉。Objection 被构建为避开干扰,并减轻维护大型 XML 容器或手动构建对象的必要性。
如有疑问,请访问 邮件列表
一个类可以通过使用宏 objection_register(可选)或 objection_register_singleton 在 Objection 中进行注册。可以使用宏 objection_requires 声明 Objection 应该向它创建的所有该类的实例提供什么依赖。使用 objection_requires 与继承一起使用是安全的。
@class Engine, Brakes;
@interface Car : NSObject
{
Engine *engine;
Brakes *brakes;
BOOL awake;
}
// Will be filled in by objection
@property(nonatomic, strong) Engine *engine;
// Will be filled in by objection
@property(nonatomic, strong) Brakes *brakes;
@property(nonatomic) BOOL awake;
@implementation Car
objection_requires(@"engine", @"brakes")
@synthesize engine, brakes, awake;
@end
您还可以使用选择器来定义依赖。如果给定的选择器不可见或找不到,则会生成编译器警告。
@implementation Car
objection_requires_sel(@selector(engine), @selector(brakes))
@synthesize engine, brakes, awake;
@end
可以通过创建一个注入器然后请求特定类的实例或协议的实例,从 Objection 中获取一个对象。注入器管理自己的对象上下文。这意味着 singleton 是每个注入器独有的,并不一定是 真正的 singleton。
- (void)someMethod {
JSObjectionInjector *injector = [JSObjection createInjector];
id car = [injector getObject:[Car class]];
}
可以将默认的注入器注册到 Objection 中,这可以在整个应用程序或库中使用。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
JSObjectionInjector *injector = [JSObjection createInjector];
[JSObjection setDefaultInjector:injector];
}
- (void)viewDidLoad {
id myModel = [[JSObjection defaultInjector] getObject:[MyModel class]];
}
可能存在对象在注入器的生命周期之外分配的情况。如果对象的类使用 objection_requires 声明依赖项,则注入器可以通过 injectDependencies: 方法来满足其依赖项。
@implementation JSTableModel
objection_requires(@"RESTClient")
- (void)awakeFromNib {
[[JSObjection defaultInjector] injectDependencies:self];
}
@end
Objection 支持下标运算符以从注入上下文中检索对象。
- (void)someMethod {
JSObjectionInjector *injector = [JSObjection createInjector];
id car = injector[[Car class]];
}
如果对象对监事可知何时由 objection 全部实例化感兴趣,则可以实现 awakeFromObjection 方法。
@implementation Car
//...
objection_register_singleton(Car)
- (void)awakeFromObjection {
awake = YES;
}
@end
一个类可以通过对象工厂从注入器上下文中获取对象。
@interface RequestDispatcher
@property(nonatomic, strong) JSObjectFactory *objectFactory
@end
@implementation RequestDispatcher
- (void)dispatch:(NSDictionary *)params
{
Request *request = [self.objectFactory getObject:[Request class]];
request.params = params;
[request send];
}
@end
模块是一组绑定,它向注入器贡献额外的配置信息。对于集成外部依赖项和将绑定协议绑定到类或实例特别有用。
@interface MyAppModule : JSObjectionModule {
}
@end
@implementation MyAppModule
- (void)configure {
[self bind:[UIApplication sharedApplication] toClass:[UIApplication class]];
[self bind:[UIApplication sharedApplication].delegate toProtocol:@protocol(UIApplicationDelegate)];
[self bindClass:[MyAPIService class] toProtocol:@protocol(APIService)];
}
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
JSObjectionInjector *injector = [JSObjection createInjector:[[MyAppModule alloc] init]];
[JSObjection setDefaultInjector:injector];
}
有时,一个依赖项(通常是外部依赖项)仅通过类方法实现。Objection 可以通过协议显式支持绑定到元类实例。这样可以避免不必要的创建包装类,该包装类传递到类方法。当然,这需要协议定义,以便 Objection 知道如何将元类绑定到注入器上下文中的对象。
@protocol ExternalUtility
- (void)doSomething;
@end
@interface ExternalUtility
+ (void)doSomething;
@end
@implementation ExternalUtility
+ (void)doSomething {...}
@end
// Module Configuration
- (void)configure {
[self bindMetaClass:[ExternalUtility class] toProtocol:@protocol(ExternalUtility)];
}
@interface SomeClass
{
...
}
// Use 'assign' because a meta class is not subject to the normal retain/release lifecycle.
// It will exist until the application is terminated (Class Initialization -> Application Termination)
// regardless of the number of objects in the runtime that reference it.
@property (nonatomic, assign) id<ExternalUtility> externalUtility
@end
偶尔您希望在使用 Objection 时手动构建对象。提供者允许您使用自定义机制来构建已绑定到类型的对象。您可以创建一个符合 ObjectionProvider 协议的类,或者使用一个 block 来构建对象。
@interface CarProvider : NSObject <JSObjectionProvider>
@end
@implementation CarProvider
- (id)provide:(JSObjectionInjector *)context arguments:(NSArray *)arguments {
// Manually build object
return car;
}
@end
@implementation MyAppModule
- (void)configure {
[self bindProvider:[[CarProvider alloc] init] toClass:[Car class]];
[self bindBlock:^(JSObjectionInjector *context) {
// Manually build object
return car;
} toClass:[Car class]];
}
@end
一个类可以被模块作为单例作用域。相反,注册的单例可以被降级到注入器上下文中的正常生命周期。
@implementation MyAppModule
- (void)configure {
[self bindClass:[Singleton class] inScope:JSObjectionScopeNormal];
[self bindClass:[Car class] inScope:JSObjectionScopeSingleton];
}
@end
可以使用 objection_requires_names 宏通过命名来标识具有相同类或协议的依赖项,该宏接受一个字典,其中包含名称到属性的映射。
@interface ShinyCar : NSObject
@property (nonatomic, strong) Headlight *leftHeadlight;
@property (nonatomic, strong) Headlight *rightHeadlight;
@end
@implementation ShinyCar
objection_register(ShinyCar)
objection_requires_names((@{@"LeftHeadlight":@"leftHeadlight", @"RightHeadlight":@"rightHeadlight"}))
@synthesize leftHeadlight, rightHeadlight;
@end
@implementation NamedModule
- (void)configure
{
[self bind:[[Headlight alloc]init] toClass:[Headlight class] named:@"RightHeadlight"];
[self bindClass:[HIDHeadlight class] toClass:[Headlight class] named:@"LeftHeadlight"];
}
@end
您可以标记注册的单例类为渴望单例。渴望单例将在创建注入器期间实例化,而不是按需实例化。
@implementation MyAppModule
- (void)configure {
[self registerEagerSingleton:[Car class]];
}
@end
可以使用 withModule: 方法从现有注入器创建一个新的注入器。新的注入器将包含与派生其的注入器相同的绑定。新的注入器还将包含由新模块提供的新绑定。
相反,如果使用 withoutModuleOfType:,则新注入器将不包含已移除模块的绑定。
injector = [otherInjector withModule:[[Level18Module alloc] init]]
withoutModuleOfType:[Level17Module class]];
默认情况下,Objection 使用默认初始化器 init
分配对象。如果您想使用不同的初始化器创建对象,可以使用 objection_initializer
宏来实现。此外,该宏还支持传入默认参数(目前不支持标量值)。
@implementation ViewController
objection_initializer(initWithNibName:bundle:, @"ViewController")
@end
@implementation ConfigurableCar
objection_requires(@"engine", @"brakes")
objection_initializer(initWithMake:model:)
@synthesize make;
@synthesize model;
- (instancetype)initWithMake:(NSString *)make model:(NSString *)model {
...
}
@end
- (void)buildCar {
ConfigurableCar *car = [self.objectFactory getObjectWithArgs:[ConfigurableCar class], @"VW", @"Passat", nil];
NSLog(@"Make: %@ Model: %@", car.make, car.model);
}
@implementation Truck
objection_requires(@"engine", @"brakes")
objection_initializer(truckWithMake:model:)
+ (instancetype)truckWithMake:(NSString *) make model: (NSString *)model {
...
}
@end
@implementation ConfigurableCar
- (instancetype) initWithModel:(NSString *)model {
//....
}
@end
- (void)buildCar {
ConfigurableCar *car = [self.objectFactory getObject:[ConfigurableCar class], initializer: @selector(initWithModel:) withArgumentList:@[@"VW", @"Passat"]];
}
如果您使用 Kiwi 进行测试,请查看 MSSpec。它提供了使用 Objection 将模拟注入到 spec 中的便捷方式。
可以在此处下载:这里
git clone git://github.com/atomicobject/objection.git
git checkout 1.5
#import <Objection-iOS/Objection.h>
#import <Objection/Objection.h>
#import <Objection/Objection.h>
更多了解请访问 CocoaPods.
为 Objection 创建了一个配套库,名为 motion-objection
gem install motion-objection
只需在 GitHub 中搜索