- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.container = [[[MVIOCContainer alloc] init] autorelease];
//add application delegate into container
[self.container addComponent:self];
//add application window into container
[self.container addComponent:self.window];
//Add main controller into container
[self.container addComponent:[MainController class]];
//Get main controller instance from container
UIViewController *mainController =
(UIViewController *)[self.container getComponent:[MainController class]];
//place main controller view into window
[self.window addSubview:mainController.view];
[self.window makeKeyAndVisible];
return YES;
}
There is many ways how to add components into container :
[container addComponent:instance]
[container addComponent:[SomeClass class]]
[container addComponent:[SomeClass class] representing:@protocol(SomeProtocol)]
[[self.container withCache] addComponent:[SomeClass class]]
[[self.container withInitSelector:@selector(initWithNibName:bundle:) params:@"NextController", [NSBundle mainBundle], nil] addComponent:[NextController class]];
NSDictionary *deps = [NSDictionary dictionaryWithObjectsAndKeys:[SomeColaborator class], @"colaborator", nil];
[[self.container withDepsDictionary:deps] addComponent:[SomeClass class]];
Components should be returned from container on entry points. For example in the application:didFinishLaunchingWithOptions:
selector of application delegate can be used something like this:
UIViewController *mainController =
(UIViewController *)[self.container getComponent:[MainController class]];
[self.window addSubview:mainController.view];
All other components should be created throught injection as colaborators. Ideal situation is just one usage of getComponent method of container.
Great emphasis is placed on creating classes as usual. Do not to force users of this framework to inherit some special abstract class or implement protocol. So, how to make it:
//SomeController.h
@interface SomeController : UIViewController {
//autowire injection
SomeAppDelegate *injAppDelegate;
SomeService *service;
}
//make it public and to allow injection
@property(nonatomic, assign) SomeAppDelegate *appDelegate;
@property(nonatomic, retain) SomeService *service;
@property(nonatomic, retain) NextController *nextController;
@end
//SomeController.m
@implementation MainController
//inj prefix tell to container to use autowiring. So he lookup for 'SomeAppDelegate' component and inject it.
@synthesize appDelegate = injAppDelegate;
@synthesize service;
//when we use dynamic we are saying to container that we want lazy load. So collaborator is created in time when we want to use it.
@dynamic nextController;
@end
What we have seen here:
NSDictionary *deps = [NSDictionary dictionaryWithObjectsAndKeys:[SomeService class], @"service", nil];
[[self.container withDepsDictionary:deps] addComponent:[SomeController class]];
As you can see, autowiring and explicitly added in components can be mixed togehter. Dictionaries keys are names of properties and values are components representers, which are in container.
@dynamic property
. This is very useful when we are wiring controllers together.
It means situation when in some controller touch on button should open another controller and so on. Lazy load can use autowiring too.
As default container uses property injection type when adding component. But there can be more injection types. It is possible to say which type to use when adding component or it can be setted as default for all addings.
[[container withInjectionType:someInjectionType] addComponent:[SomeClass class]]
container.injectionType = someInjectionType
It is possible to write your own injection type. Just implement
protocol and use it
Caching of components is mainly used to simulate singleton behavior of components. As with injection types, there can be more caching strategies.
Framework now support just really easy caching which is in most cases good enough, but it is not thread safe. But other can be written, for example thread safe caching, or caching just in threads ...
How to use cache:
[[container withCache] addComponent:[SomeClass class]]
is using default cache strategy, which can be setted with container.cache = someCacheStrategy
[[container withCache:cacheStrategy] addComponent:[SomeClass class]]
is saying to use explicitly given cache strategyAct on component is feature, when you can say 'make some act on created component'. Library currenty implement [[Controller Actor]] which should help with controller views and subviews. It is usable, when you need to do something with instance which is just created. How to use :
MVIOCActor
protocol[[self.container actAs:yourActorInstance] addComponent:[SomeComponentsClass]];
Make note, that actor is used just when creating new component. So when you use caching, actor is run upon instance just one time.