注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

(转载)Objective -C的开发之十四IOS实现依赖注入  

2016-04-06 09:21:36|  分类: IOS |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Objective -C的开发之十四IOS实现依赖注入(转载)

 

iOS实现依赖注入

时间 2016-03-22 11:39:58  SegmentFault

原文  https://segmentfault.com/a/1190000004659514

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

 

举例来说:

 

UIView的初始化方法initWithFrame

 

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

这里的frame传入值,就是所谓的 依赖(Dependency) ,这个View实例化是根据frame注入实现的。

 

但这种用法有很大的局限性

 

我们不知道究竟依赖注入的属性有哪些

 

不可能无限加长方法长度来满足更多的依赖属性

 

所以我们准备采用字典容器对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,一个是其ViewbackgroundColor属性。

 

字典传入以后,我们读区 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实现跨实例赋值

 

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

 

  @"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 则可以轻松实现前后端分离。

 

目前的缺点也很明显,不能告诉开发者哪些属性是必需依赖,另外还不能支持非对象属性的赋值,希望抛砖引玉,大家来改进这段代码。

 

  评论这张
 
阅读(174)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017