DeluxeInjection 0.8.6

DeluxeInjection 0.8.6

测试已测试
语言 Obj-CObjective C
许可证 MIT
发布最新发布2018年3月

Anton Bukov 维护。



DeluxeInjection💉

Test Coverage

功能

  1. 自动注入作为一等特性
  2. 支持 Objective-C 类属性
  3. 支持值注入和 getter-setter 注入
  4. 注入ivar支持的和@dynamic属性(通过关联)
  5. 在注入方法中易于访问ivar和原始方法实现

目录

  1. 概念
  2. 自动注入
  3. 懒加载注入
  4. 设置注入
  5. 性能和测试
  6. 安装

概念

DeluxeInjection 库的主要概念是显式地注入标记的属性。属性可以通过协议进行标记,这就是为什么不支持整数(非对象)属性。

DeluxeInjection 有最小的 API,其中最有意思的功能被实现为独立的插件。您可以轻松地开发自己的插件,只需查看一些现有的:DIInjectDILazyDIDefaultsDIAssociate

由于 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 块参数:目标和 *ivar
  • DIGetterIfIvarIsNil 块参数:目标
  • 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 中,可以将它们存档,只需使用 DIDefaultsArchivedDIDefaultsArchivedSync 协议。

有一些 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,然后我们再聊天 :)