控制反转(IoC)容器的设计

定义

用iOS开发环境来举例,IoC容器的核心功能负责对象创建、依赖查找和依赖注入,这些功能都需要借助运行时runtime的反射实现

使用protocol

在IoC容器中,就算通过反射可以创建Class 和instance,但是实际开发过程中还是有缺陷,因为还是不能很好地访问Class的属性与方法,这时候可以通过iOS的Protocol来访问。

例子
在IoC容器中,创建一个Class的Protocol,此Protocol声明了Class的所有方法和属性,然后在Class中实现此Protocol接口便可。

//
//  ClassAProtocol.h
//  IOCAdapter
//

#ifndef ClassAProtocol_h
#define ClassAProtocol_h

NS_ASSUME_NONNULL_BEGIN

@protocol ClassAProtocol <NSObject>

@property (nonatomic, copy) NSString *var;

- (void)testMethod;

+ (void)testClassMethod;
@end

NS_ASSUME_NONNULL_END


#endif /* ClassAProtocol_h */
#import <Foundation/Foundation.h>
#import <IOCAdapter/ClassAProtocol.h>

NS_ASSUME_NONNULL_BEGIN

@interface ClassA : NSObject <ClassAProtocol>

@property (nonatomic, copy) NSString *var;

- (void)testMethod;

+ (void)testClassMethod;


@end

NS_ASSUME_NONNULL_END

IoC容器 Class缓存

因为从IoC容器中获取Class的次数较为频繁,我们可以在容器中加入缓存功能。


@interface IOCCacheServiceDict:NSObject

+ (instancetype)sharedInstance;

- (Class) getClass:(NSString*) key;

- (void) addService:(NSString*) key implClass:(Class) implClass;

@end


@implementation IOCCacheServiceDict{
    NSMutableDictionary *_dictServices;
    NSRecursiveLock *_lock;
}

+ (instancetype)sharedInstance{
    static dispatch_once_t onceToken;
    static IOCCacheServiceDict* dict;
    dispatch_once(&onceToken, ^{
        dict = [[self alloc] init];
    });
    return dict;
}

- (instancetype)init{
    self = [super init];
    if (!self) {
        return nil;
    }
    _dictServices = [NSMutableDictionary dictionaryWithCapacity:25];
    _lock = [[NSRecursiveLock alloc] init];
    return self;
}


- (Class) getClass:(NSString*) key{
    [_lock lock];
    Class cls = _dictServices[key];
    [_lock unlock];
    return cls;
}

- (void) addService:(NSString*) key implClass:(Class) implClass{
    [_lock lock];
    [_dictServices setValue:implClass forKey:key];
    [_lock unlock];
}

@end

获取Class


Class IOCGetServiceClass(Protocol* protocol){
    NSString* protocolName = NSStringFromProtocol(protocol);
    Class cls = [[IOCCacheServiceDict sharedInstance] getClass:protocolName];
    if (nil != cls){
        return cls;
    }
    NSString *protocolSubffix = @"Protocol";
    return IOCGetServiceClassWithProtocol(protocol, protocolName, protocolSubffix);

}

Class IOCGetServiceClassWithProtocol(Protocol* protocol, NSString* protocolName, NSString* protocolSubffix){
    NSString *className = [protocolName hasSuffix:protocolSubffix] ? [protocolName substringToIndex:protocolName.length - protocolSubffix.length] : protocolName;
    Class cls = NSClassFromString(className);
    IOCRegisterServiceForStringProtocol(protocolName, cls);

    return cls;
}

BOOL IOCRegisterServiceForStringProtocol(NSString* protocol, Class implClass){
    if (nil == protocol || nil == implClass){
        return NO;
    }
    if ([[IOCCacheServiceDict sharedInstance] getClass:protocol]) {
        return NO;
    }else{
        [[IOCCacheServiceDict sharedInstance] addService:protocol implClass:implClass];
        return YES;
    }
}

获取 instance


id IOCGetServiceInstance(Protocol* protocol){
    Class cls = IOCGetServiceClass(protocol);
    id value = [cls new];
    return value;
}

调用

在不同的模块中,可以通过以下方法,来访问其他模块的Class和Class的属性、方法。

[IOCGetServiceClass(@protocol(ClassAProtocol)) testClassMethod];

[IOCGetServiceInstance(@protocol(ClassAProtocol)) testMethod];

[IOCGetServiceInstance(@protocol(ClassAProtocol)) var];
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 夜莺2517阅读 127,751评论 1 9
  • 版本:ios 1.2.1 亮点: 1.app角标可以实时更新天气温度或选择空气质量,建议处女座就不要选了,不然老想...
    我就是沉沉阅读 6,939评论 1 6
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,587评论 28 53
  • 兔子虽然是枚小硕 但学校的硕士四人寝不够 就被分到了博士楼里 两人一间 在学校的最西边 靠山 兔子的室友身体不好 ...
    待业的兔子阅读 2,633评论 2 9