blog

iOSプロジェクト開発のモジュール化にObjectionを使う

objection は、Guice にインスパイアされた軽量な依存性注入フレームワークで、Google Wallet もこのプロジェクトを使っています。「依存性注入はオブジェクト指向プログラミングのデ...

Jan 12, 2016 · 4 min. read
シェア

ViewControllerA.viewにボタンがあり、それをクリックするとViewControllerBがプッシュされるというシナリオを想定した場合、最もシンプルな書き方は以下のようになります:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; 
    button.frame = CGRectMake(100, 100, 100, 30); 
    [button setTitle:@"Button" forState:UIControlStateNormal]; 
    [button addTarget:self action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside]; 
    [self.view addSubview:button]; 
} 
 
- (void)buttonTapped 
{ 
    ViewControllerB *vc = [[ViewControllerB alloc] init]; 
    [self.navigationController pushViewController:vc animated:YES]; 
} 

この書き方で問題になるのは、ViewControllerA が ViewControllerB をインポートする必要があることです。依存関係が増えれば増えるほど、メンテナンスが面倒になり、循環依存関係が発生しやすくなります。

実装方法は次のとおりです。最初にプロトコルを定義し、このプロトコルに対応するクラスを登録する異議申し立てを通じて、必要なときに、プロトコルの対応するオブジェクトを取得することができます。これにより、特定のクラスに依存する必要がなくなります。これはしばしば「インターフェース指向プログラミング」と呼ばれます。

JSObjectionInjector *injector = [JSObjection defaultInjector]; // [1] 
UIViewController <ViewControllerAProtocol> *vc = [injector getObject:@protocol(ViewControllerAProtocol)]; // [2] 
vc.backgroundColor = [UIColor lightGrayColor]; // [3] 
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc]; 
self.window.rootViewController = nc; 

[ViewControllerAProtocol に対応するオブジェクトを取得します。

[このプロパティは ViewControllerAProtocol で定義されているため、警告は発生しません。

@interface ViewControllerAModule : JSObjectionModule 
@end 
 
@implementation ViewControllerAModule 
- (void)configure 
{ 
    [self bindClass:[ViewControllerA class] toProtocol:@protocol(ViewControllerAProtocol)]; 
} 
@end 

バインディング操作は configure メソッドで行われ、オブジェクトに追加されると自動的に起動します。

JSObjectionInjector *injector = [JSObjection defaultInjector]; // [1] 
injector = injector ? : [JSObjection createInjector]; // [2] 
injector = [injector withModule:[[ViewControllerAModule alloc] init]]; // [3] 
[JSObjection setDefaultInjector:injector]; // [4] 

[1] デフォルトのインジェクターを取得

[2] デフォルトのインジェクタが存在しない場合は、新しいインジェクタを作成してください。

[3] モジュールをインジェクターに登録します。

[4] このインジェクターをデフォルトインジェクターに設定します。

このコードは+loadで直接実行できるので、AppDelegateで様々なModuleをインポートする必要がありません。

対応するクラスを直接取得することはできないため、外部で公開されるメソッドやプロパティはプロトコルで定義し、クラスもそのプロトコルを実装する必要があります。

@protocol ViewControllerAProtocol <NSObject> 
@property (nonatomic) NSUInteger currentIndex; 
@property (nonatomic) UIColor *backgroundColor; 
@end 
 
@interface ViewControllerA : UIViewController <ViewControllerAProtocol> 
@end 

各セクションは、異なる人々を担当することができ、その後、行に一緒に張ったが、また、MVC(Mess View Controller)の出現を避けるために、ある程度まで。

総合的に見ると、このlibは今でもかなり信頼性が高く、2年以上メンテナンスされていますし、使っているプロジェクトもいくつかあり、開発メンバーの効率化にもかなり役立つと思いますので、一度使ってみることを検討してみてはいかがでしょうか。

転載

Read next

vSphere クライアントでの光学ドライブの設定方法

物理マシンでインストールファイルを実行する場合は、光学ドライブに DVD を挿入できますが、仮想マシンには DVD ドライブがありません。仮想マシンをインストールする場合、vSphere クライアントを使用して仮想マシンで使用する光学ドライブ デバイスを構成する方法を検討する必要があります。

Jan 12, 2016 · 2 min read