DeluxeInjection 库的主要概念是显式地注入标记的属性。属性可以通过协议进行标记,这就是为什么不支持整数(非对象)属性。
DeluxeInjection 有最小的 API,其中最有意思的功能被实现为独立的插件。您可以轻松地开发自己的插件,只需查看一些现有的:DIInject
、DILazy
、DIDefaults
、DIAssociate
。
由于 DeluxeInjection 的架构,大多数插件都是通过枚举所有类的所有属性来工作的。使用多个插件时不是很有效,因此实现了 DIImperative
插件,并且所有其他插件现在都支持 DIImperative
插件。它收集所有类的所有可注入属性,并提供一个块来以命令形式应用所有必要的注入。此插件被用作 DeluxeInjection 的默认用法。
这是一个基本的示例,通过类和协议注入值以及 getter 注入
@interface MyClass : NSObject
@property (nonatomic) Settings<DIInject> *settings;
@property (nonatomic) id<Analytics,DIInject> *analytics;
@property (nonatomic) NSMutableArray<UIVIew *><DIInject> *items;
@end
创建一些将被注入的实例
Settings *settings = [UserDefaultsSetting new];
Analytics *analytics = [CountlyAnalytics new];
将实例和块注入到属性中
[DeluxeInjection imperative:^(DIImperative *lets) {
// Inject value by class
[[[lets inject] byPropertyClass:[Settings class]]
getterValue:settings];
// Inject value by property protocol
[[[lets inject] byPropertyProtocol:[Analytics class]]
getterValue:analytics];
// Inject getter by property class
[[[lets inject] byPropertyClass:[NSMutableArray class]]
getterBlock:DIImperativeGetterFromGetter(DIGetterMake(^id (id target, id *ivar) {
if (*ivar == nil) {
*ivar = [NSMutableArray array];
}
return *ivar;
}))];
}];
您可以注入值、getter 和 setter 块。有一些函数可以简化 getter(setter 同样适用,加上附加的参数 value
)块的声明
DIGetterMake
块参数:目标和 *ivarDIGetterIfIvarIsNil
块参数:目标DIGetterWithOriginalMake
块参数:目标、*ivar 和原始 getter 指针您真的喜欢这个样板代码吗?
@interface SomeClass : SomeSuperclass
@property (nonatomic) NSMutableArray *items;
@end
@implementation SomeClass
- (NSMutableArray *)items {
if (_items == nil) {
_items = [NSMutableArray array];
}
return items;
}
@end
只需一个关键字即可为您做到这一切
@interface SomeClass : SomeSuperclass
@property (nonatomic) NSMutableArray<DILazy> *items;
@end
当然,这将为通用类型工作
@property (nonatomic) NSMutableArray<NSString *><DILazy> *items;
@property (nonatomic) NSMutableDictionary<NSString *, NSString *><DILazy> *items;
所有这些将在调用 injectLazy
后注入
[DeluxeInjection imperative:^(DIImperative *lets) {
...
[lets injectLazy];
...
}];
希望用更少的模板代码实现这种行为吗?
@interface SomeClass : SomeSuperclass
@property (nonatomic) NSString *username;
@end
@implementation SomeClass
- (NSString *)username {
return [[NSUserDefaults standardUserDefaults] stringForKey:@"username"];
}
- (void)setUsername:(NSString *)username {
return [[NSUserDefaults standardUserDefaults] setValue:username forKey:@"username"];
}
@end
只需在属性声明中使用 <DIDefaults>
或 <DIDefaultsSync>
协议。
@interface SomeClass : SomeSuperclass
@property (nonatomic) NSString<DIDefaults> *username;
@end
通过调用 injectDefaults
进行注入。
[DeluxeInjection imperative:^(DIImperative *lets) {
...
[lets injectDefaults];
...
}];
如果某些内容不能直接存储到 NSUserDefault 中,可以将它们存档,只需使用 DIDefaultsArchived
或 DIDefaultsArchivedSync
协议。
有一些 injectDefaults
方法的扩展版本来提供密钥生成器和使用不同的 NSUserDefaults
实例。
injectDefaultsWithKeyBlock
injectDefaultsWithDefaultsBlock
injectDefaultsWithKeyBlock:injectDefaultsWithKeyBlock
!!!警告 DIForceInject
插件不能以 DIImperative
方式使用,而应单独使用。
您可以强制注入任何类的任何属性。
@interface TestClass : SomeSuperclass
@property (nonatomic) Network *network;
@end
即使没有任何协议规定,也无需使用 forceInject:
方法。
Network *network = [Network alloc] initWithSettings: ... ];
[DeluxeInjection forceInject:^id(Class targetClass,
NSString *propertyName,
Class propertyClass,
NSSet<Protocol *> *protocols) {
if ([target isKindOfClass:[TestClass class]] &&
propertyClass == [Network class]) {
return network;
}
return [DeluxeInjection doNotInject]; // Special value to skip injection
}];
指定的块将被调用以针对所有类的所有属性(排除符合任何 DI***
协议的属性),您应该确定在此属性中注入哪个值,或者根本不注入。您还可以使用方法 forceInjectBlock:
来返回 DIGetter
块,而不是值,以提供注入的获取器。
在 iPhone 6s
上以 DEBUG
配置,一次性枚举 40,000 个类中的 100,000 个属性,注入 150 个属性需要 0.082 秒。未来版本的性能不会下降,这是库的第一个一级特性,性能极强。您可以在示例项目中找到一些性能测试和其他测试。我打算添加更多测试以检测所有可能出现的问题。也许您愿意帮助我进行测试?
要运行示例项目,首先从 Example 目录克隆仓库,然后运行 pod install
。
DeluxeInjection 通过 CocoaPods 提供。要安装它,请只需将其添加到您的 Podfile 中:
pod 'DeluxeInjection'
Anton Bukov [email protected] https://twitter.com/k06a
DeluxeInjection 在 MIT 许可证下提供。有关更多信息,请参阅 LICENSE 文件。
– 想真正帮助项目吗?
– 帮助我添加更多测试并将它们按插件分类。
– 发现任何错误吗?
– 欢迎您直接提出问题或直接与我联系 @k06a!
贡献流程
1. 分叉仓库
2. 从 master 创建新分支
3. 将更改提交到您的全新创建的分支
4. 打开 Pull Request,然后我们再聊天 :)