反对意见 1.6.1

Objection 1.6.1

测试已测试
Lang语言 Obj-CObjective-C
许可证 自定义
发布最后发布2015年7月

Justin DeWind维护。



Objection 1.6.1

  • 编者:
  • Justin DeWind

描述

Objection 是一个面向 MacOS X 和 iOS 的 Objective-C 的轻量级依赖注入框架。对于那些使用过 Guice 的人来说,Objection 会感觉熟悉。Objection 被构建为避开干扰,并减轻维护大型 XML 容器或手动构建对象的必要性。

特性

  • 基于注解的依赖注入
  • 无缝支持集成自定义和外部依赖
    • 自定义对象提供者
    • 元类绑定
    • 协议绑定
    • 实例绑定
    • 命名绑定
  • 延迟实例化依赖
  • 积极 singleton
  • 初始化器支持
    • 默认和自定义参数

使用Objection

如有疑问,请访问 邮件列表

基本用法

一个类可以通过使用宏 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获取对象

可以通过创建一个注入器然后请求特定类的实例或协议的实例,从 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 唤醒

如果对象对监事可知何时由 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

模块

模块是一组绑定,它向注入器贡献额外的配置信息。对于集成外部依赖项和将绑定协议绑定到类或实例特别有用。

实例和协议绑定

  • 将协议或类绑定到该类型的特定实例
  • 将已注册到 Objection 的类绑定到协议

示例

@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 中的便捷方式。

TODO

  • 添加一个动机部分,说明创建 Objection 的原因。

安装

静态框架和链接框架

可以在此处下载:这里

构建静态框架

git clone git://github.com/atomicobject/objection.git
git checkout 1.5

iOS

  1. rake artifact:ios
  2. cp -R build/Release-iphoneuniversal/Objection-iOS.framework ${DEST_DIR}
  3. 在 XCode -> Project Icon -> Your Target -> Build Phases -> Link Binary With Libraries -> Add (+) -> Add Other
  4. 在项目的其他链接标志中添加 -ObjC 和 -all_load

包含框架

#import <Objection-iOS/Objection.h>

MacOS X

  1. rake artifact:osx
  2. cp -R build/Release/Objection.framework ${DEST_DIR}
  3. 在 XCode -> Project Icon -> Your Target -> Build Phases -> Link Binary With Libraries -> Add (+) -> Add Other

包含框架

#import <Objection/Objection.h>

包含框架

#import <Objection/Objection.h>

更多了解请访问 CocoaPods.

Ruby Motion

为 Objection 创建了一个配套库,名为 motion-objection

gem install motion-objection

要求

  • MacOS X 10.8+
  • iOS 7.0+

作者

其他依赖注入库

只需在 GitHub 中搜索

使用 Objection 的应用程序