Objection 与 Typhoon 的协议绑定对比

ObjectionTyphoon 都是 Objective-C 中的依赖注入框架,两者都很强大,在 GitHub 上的 star 都超过一千,前者更加轻量级,后者文件数量较多,不但支持 Swift,而且貌似支持 Storyboard,Core Data。

之前看过 Limboy 的使用 objection 来模块化开发 iOS 项目,文章中提到了通过将协议和对应的实现类进行绑定,从而达到模块化开发,那么我们就从这个实现机制来看看两者的一些区别。

协议绑定(Protocol binds)的实现

所谓的协议绑定,其实也就是面向接口编程,相关文章可以看看这篇

实现协议绑定,我们可以从以下方面进行对比:

  • 依赖注入框架初始化
  • 协议与实现类的绑定
  • 外部的调用

那么先新建以下文件作为准备:

@protocol AnimalProtocol <NSObject>

- (void)eat;

@end
@interface Dog : NSObject<AnimalProtocol>

@end

@implementation Dog

- (void)eat{
NSLog(@"dog eat");
}

@end
  • 首先制定一个协议(AnimalProtocol)
  • 然后由 Dog 遵循并实现了这个协议

Objection 的实现

新建一个 baseModule 类继承至 JSObjectionModule

步骤一初始化 injector,

步骤二进行绑定操作。

@interface BaseModule : JSObjectionModule

// 1.
+ (void)load {
JSObjectionInjector *injector = [JSObjection defaultInjector];
injector = injector ? : [JSObjection createInjector];
injector = [injector withModule:[[self alloc] init]];
[JSObjection setDefaultInjector:injector];
}

// 2.
- (void)configure {
[self bindClass:[Dog class] toProtocol:@protocol(AnimalProtocol)];
}
@end

然后就可以在控制器或者其他地方,通过这个协议获取对应的类:

id<AnimalProtocol> animal = [[JSObjection defaultInjector] getObject:@protocol(AnimalProtocol)];

[animal eat];

看起来不难,我们再看下 Typhoon 的实现。

Typhoon 的实现

先在工程项目里面的 info.plist 进行配置,这样 BaseModule 的绑定操作就会在程序启动后自动完成:

然后就可以在 BaseModule 里面进行绑定操作,并且这里继承了 TyphoonAssembly:

@class TestViewController;
@protocol AnimalProtocol;
@interface BaseModule : TyphoonAssembly

- (TestViewController *)testViewController;
- (id<AnimalProtocol>)animal;

@end
@implementation BaseModule

- (TestViewController *)testViewController{
return [TyphoonDefinition withClass:[TestViewController class] configuration:^(TyphoonDefinition *definition) {
[definition injectProperty:@selector(animal) with:[self animal]];
}];
}

- (id<AnimalProtocol>)animal{
return [TyphoonDefinition withClass:[Dog class]];
}

@end

这里直接将 Dog 实例直接注入到 TestViewController,那么每个 TestViewController 对象都直接持有 Dog 对象,不在需要 alloc,init 等操作。

@interface TestViewController ()

@property (nonatomic, strong)id<AnimalProtocol> animal;

@end

@implementation TestViewController

- (void)viewDidLoad {
[super viewDidLoad];

[self.animal eat];
}

看似在 BaseModule 里面的代码有点繁琐,但是可定制程度更高。

小结

无论是协议绑定还是要模块化,都有个目的是为了摆脱对某个类的依赖,减少代码之间的耦合。当需求调整的时候,我们可以直接将 AnimalProtocol 所对应的 Dog 换成其他类,而不需要对每处代码都进行修改。现实情况下,这可以是一个抽象类,或是某个控制器,甚至还可以用来实现多继承。

前面的示例中,Objection 为了获取 Dog 对象,又不得不在外部依赖 JSObjectiongetObject,相较之下,Typhoon 则可以直接持有已经初始化好的对象,代码更加干净。另外,这两个库还有很多强大的功能,这里未再进一步探索。感兴趣可以继续查看它们的 GitHub 和相关 Demo。