盲点可以帮助您编写干净的代码。您可以保持对象松散耦合,并且对外界的知识一无所知。您的对象可以创建其他对象,而无需了解其他对象的依赖。
这是一个关于对象应该对外部依赖的来源“瞎”的概念。然而,绝大多数情况下,将其命名为“BSInjector”、“BSProvider”等是非常有趣的。
抱歉,是的。在语言提供的对象级依赖管理方面,Objective-C 和 Java 是相同的:基本上没有。全局变量、“singleton”单例和透传参数是常见的访问依赖模式的选项。它们都不是一个好的选择。
Guice 将优雅的对象级依赖管理带到了 Java,消除了静态数据的需求,并实现了真正的面向对象编程的承诺。盲点试图为 Objective-C 做同样的事情。
盲点是 alpha 软件版本。除了这段说明文档外,没有其他文档。我的重点现在是构建文档和示例。我在当前的 iOS 项目中使用它,并且运行良好。以这种状态发布了它,看看是否会引起任何兴趣。如果您已经看到了这段说明文档并有一些问题,或者想要了解更多关于如何使用盲点,请与我联系。
您描述您的对象的依赖,定义填充这些依赖的绑定,然后要求 BSInjector 创建您的对象。这里有一个“Hello,World”示例
/**
* 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
显然,对于这种微不足道的工作,你不需要框架。Blindside 确实在 MyViewController 创建另一个视图控制器时非常有用,而这个控制器又创建了另一个,并包含额外的依赖项,依此类推。
Blindside 通过两种方式向对象提供依赖:通过初始化器(例如:initWithDelegate:)或使用属性。您可以将这两种方法混合使用。
Blindside 需要两个类方法来描述依赖关系。这些方法被添加到 NSObject 的 NSObject+Blindside 类别中,并意在被注入 Blindside 的类所重写。这些方法是
bsInitializer 描述了创建类的实例时使用的初始化方法,包括初始化者的选择器和参数。Blindside 可以使用类的 BSInitializer 创建类的实例,并注入依赖项。
bsProperties 描述了将要注入到已创建的对象中的属性。
以下是一个用于名为 House 的类的两个方法实现的示例。House 类作为初始化参数接受一个 Address,并具有一个 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;
}
...
在处理属性注入时,有时希望有一个钩子,可以在所有依赖注入完成后用于完成对象的设置。Blindside 为此提供了一个机制
@implementation House
- (void)bsAwakeFromPropertyInjection {
// Finalize instantiation
}
...
请注意,不推荐使用此方法,因为它会增加您的代码与 Blindside 之间的耦合。首先,在对象上寻找其他适当的生命周期方法(例如视图控制器上的 -viewDidLoad
),以便可以执行此类工作。
您也可以在 Swift 中使用 Blindside。首先,将 #import <Blindside/Blindside.h>
添加到 Swift 的桥接头文件中,以便将框架暴露给 Swift 代码。
创建一个类似于 Objective-C 的注入器
let module = MyBlindsideModule()
let injector = Blindside.injectorWithModule(module)
为了无参数实例化您的控制器
let controller = injector.getInstance(MyViewController.self)
要传递动态参数(标记为 BS_DYNAMIC
的参数)到您的控制器,请使用新提供的 -getInstance:withArgArray:
方法。
let controller = injector.getInstance(MyViewController.self, withArgArray: [BSNull(), "arg"])
如此描述类的依赖关系
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
}
}
请注意,Blindside 仅能创建和注入 NSObject 派生类。
版权所有 © 2012 JB Steadman。本软件根据 MIT 许可证授权。