iOS依赖注入

作者: 秋刀生鱼片 | 来源:发表于2016-03-22 15:18 被阅读704次

源码

依赖注入(Dependency Injection)这个词,源于java,但在Cocoa框架中也是十分常见的。
举例来说:
UIView的初始化方法initWithFrame

- (id)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;

这里的frame传入值,就是所谓的依赖(Dependency),这个View实例化是根据frame注入实现的。
但这种用法有很大的局限性

  1. 我们不知道究竟依赖注入的属性有哪些
  2. 不可能无限加长方法长度来满足更多的依赖属性

所以我们准备采用字典容器对NSObject类进行依赖注入扩展。

给NSObject类添加一个Category

@interface NSObject (XXXDependencyInjection)

- (nullable id)initWithParams:(nonnull NSDictionary *)params;
- (void)injection:(nonnull NSDictionary*)params;

@end

实现注入方法

- (id)initWithParams:(NSDictionary *)params
{
    self = [self init];
    if (self) {
        [self injection:params];
    }
    return self;
}

- (void)injection:(NSDictionary*)params
{
    [params.allKeys enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",[[obj substringToIndex:1] uppercaseString],[obj substringFromIndex:1]]);
        id value = [params objectForKey:obj];
        
        
        if ([self respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [self performSelector:selector withObject:value];
#pragma clang diagnostic pop
        }
        else
        {
            @try {
                [self setValue:value forKeyPath:obj];
            }
            @catch (NSException *exception) {
                NSLog(@"%@",exception);
                [exception raise];
            }
            @finally {
                
            }
        }
    }];
}

解释

我们将需要注入的属性,封装到一个字典里,例如:

UIViewController* controller = [[UIViewController alloc] initWithParams:@{
                               @"title":@"测试",
                               @"view.backgroundColor":[UIColor whiteColor]
                                                                              }];

我们给这个VC注入了两个属性,一个是其title,一个是其View的backgroundColor属性。
字典传入以后,我们读区params.allKeys进行遍历,拼装set+参数名的selector,这里用的是NSSelectorFromString方法:

SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",[[obj substringToIndex:1] uppercaseString],[obj substringFromIndex:1]]);

然后我们判断实例是否可以响应这个set方法,如果可以,则给其赋值。

        if ([self respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [self performSelector:selector withObject:value];
#pragma clang diagnostic pop
        }

这里的三行clang宏是为了消除编译器的内存泄漏警告,这里因为我们进行了验证,所以不会出现leak。

KVC实现跨实例赋值

我们注意到上例中还有一句给VC的View改变背景颜色

  @"view.backgroundColor":[UIColor whiteColor]

这里就用到了KVC的点语法特性,在我们判断到实例不能响应if ([self respondsToSelector:selector])的时候,通过点语法,进行赋值

@try {
    [self setValue:value forKeyPath:obj];
}
@catch (NSException *exception) {
    NSLog(@"%@",exception);
   [exception raise];
}
@finally {

}

这里添加了异常捕获,因为点语法对属性名称拼写要求是全匹配,否则抛异常,所以要注意。

优缺点

这样改造过的init方法,优点非常明显,就是绑定更加集中便捷,如果使用的是storyboard则可以轻松实现前后端分离。
目前的缺点也很明显,不能告诉开发者哪些属性是必需依赖,另外还不能支持非对象属性的赋值(已经可以,改为setValueforkeyPath方法赋值),希望抛砖引玉,大家来改进这段代码。

相关文章

  • [iOS]一次高效的依赖注入

    [iOS]一次高效的依赖注入 [iOS]一次高效的依赖注入

  • iOS App MachO注入 - Dylib注入

    iOS App MachO注入 - Dylib注入 dylib 注入 1. 新建TARGETS 2. 添加依赖关系...

  • iOS 依赖注入

    iOS 依赖注入 最近读项目代码的总结! 什么是依赖呢,会有什么问题呢?平时写代码,这种依赖的方式太常见了。 看代...

  • iOS依赖注入

    源码 依赖注入(Dependency Injection)这个词,源于java,但在Cocoa框架中也是十分常见的...

  • 依赖注入,iOS

    作者:Graham Lee 翻译:蜂猴 面向对象编程其实就是对于你的软件问题的一个基于对象之间的关联网和它们之间所...

  • 依赖注入-iOS

    依赖 依赖:在ClassA(调用者)中初始化ClassB(被调用者)的实例,那么ClassA对ClassB有一个依...

  • [IOS架构]Swinject 依赖注入框架

    在本文中,我将介绍依赖注入的基础知识,以及如何使用Swinject框架将依赖注入应用到iOS项目中。 什么是依赖 ...

  • ios项目依赖注入

    依赖注入(Dependency Injection) 依赖注入最大的特点就是:帮助我们开发出松散耦合(loose ...

  • 开源项目的依赖注入

    开源项目的依赖注入 依赖注入概念 依赖注入(DI:Dependency Injection): 依赖注入方式: B...

  • 资料收集

    依赖注入 AngularJs依赖注入的研究 (已读) 依赖注入(已读)

网友评论

  • 庚鑫:"如果使用的是storyboard则可以轻松实现前后端分离" 这句话可以展开来讲一下吗
    秋刀生鱼片:文章久远,见谅。 我估计我是想说 不使用storyboard的时候,用initWithParams初始化UI, 使用storyboard 的情况下,直接使用injection方法注入,所谓前后端分离,指的是storyboard 负责样式布局,代码负责数据内容,在数据内容代码不变的情况下,通过修改storyboard就可以更新UI,就是所谓的前后分离。

本文标题:iOS依赖注入

本文链接:https://www.haomeiwen.com/subject/zghllttx.html