[[RequestManager sharedInstance] loadResourcesAtPath:@"http://example.com/resources" withDelegate:self]; // [[DatabaseManager sharedManager] saveResource:resource];
@interface ViewController : UIViewController @property (nonatomic, strong) RequestManager *requestManager; @end
requestManager
as a singleton in the application, but in tests replacing it with a mock. At the same time, neither RequestManager
nor ViewController
knows anything about singletons, because this behavior controls the DI framework. @interface ViewController : UIViewController @property (nonatomic, strong) ProgressViewService *progressViewService; @property (nonatomic, strong) ResourceLoader *resourceLoader; @end @implementation ViewController - (void)loadResources { [self.progressViewService showProgressInView:self.view]; self.resourceLoader.delegate = self; [self.resourceLoader loadResources]; } - (ProgressViewService *)progressViewService { if (_progressViewService == nil) { _progressViewService = [ProgressViewService new]; } return _progressViewService; } - (ResourceLoader *)resourceLoader { if (_resourceLoader == nil) { _resourceLoader = [ResourceLoader new]; } return _resourceLoader; } @end
@interface ViewController : UIViewController <BMLazy> @property (nonatomic, strong, bm_lazy) ProgressViewService *progressViewService; @property (nonatomic, strong, bm_lazy) ResourceLoader *resourceLoader; @end @implementation ViewController @dynamic progressViewService; @dynamic resourceLoader; - (void)loadResources { [self.progressViewService showProgressInView:self.view]; self.resourceLoader.delegate = self; [self.resourceLoader loadResources]; } @end
@dynamic
properties will be created when you first call self.progressViewService
and self.resourceLoader
. These objects will be freed as well as ordinary properties - after the release of ViewController
.+new
used to create objects. But it is possible to describe your own custom initializers, which are a key feature of BM as a DI framework. BMInitializer *initializer = [BMInitializer lazyInitializer]; initializer.propertyClass = [ProgressViewService class]; initializer.initializer = ^id (id sender){ return [[ProgressViewService alloc] initWithViewController:sender]; }; [initializer registerInitializer];
propertyClass
- initializer is registered for properties of this class.initializer
- the block that will be called to initialize the object. If this block is nil
or the initializer is not found, then the object will be created using the +new
method.sender
is an instance of a container class.containerClass
, which allows you to describe the creation of the same property in different ways, based on the container. For example: BMInitializer *usersLoaderInitializer = [BMInitializer lazyInitializer]; usersLoaderInitializer.propertyClass = [ResourceLoader class]; usersLoaderInitializer.containerClass = [UsersViewController class]; usersLoaderInitializer.initializer = ^id (id sender){ return [ResourceLoader usersLoader]; }; [usersLoaderInitializer registerInitializer]; BMInitializer *projectsLoaderInitializer = [BMInitializer lazyInitializer]; projectsLoaderInitializer.propertyClass = [ResourceLoader class]; projectsLoaderInitializer.containerClass = [ProjectsViewController class]; projectsLoaderInitializer.initializer = ^id (id sender){ return [ResourceLoader projectsLoader]; }; [projectsLoaderInitializer registerInitializer];
UsersViewController
and ProjectsViewController
. By default, containerClass
is equal to the class NSObject
.shared*
methods and hardcodes described at the beginning of the article: BMInitializer *initializer = [BMInitializer lazyInitializer]; initializer.propertyClass = [RequestManager class]; initializer.initializer = ^id (id sender){ static id singleInstance = nil; static dispatch_once_t once; dispatch_once(&once, ^{ singleInstance = [RequestManager new]; }); return singleInstance; }; [initializer registerInitializer];
lazy_initializer
. All you need is to create a file without a header and add it to the compilation phase. // LoaderInitializer.m #import <BloodMagic/Lazy.h> #import "ResourceLoader.h" #import "UsersViewController.h" #import "ProjectsViewController.h" lazy_initializer ResourseLoaderInitializers() { BMInitializer *usersLoaderInitializer = [BMInitializer lazyInitializer]; usersLoaderInitializer.propertyClass = [ResourceLoader class]; usersLoaderInitializer.containerClass = [UsersViewController class]; usersLoaderInitializer.initializer = ^id (id sender){ return [ResourceLoader usersLoader]; }; [usersLoaderInitializer registerInitializer]; BMInitializer *projectsLoaderInitializer = [BMInitializer lazyInitializer]; projectsLoaderInitializer.propertyClass = [ResourceLoader class]; projectsLoaderInitializer.containerClass = [ProjectsViewController class]; projectsLoaderInitializer.initializer = ^id (id sender){ return [ResourceLoader projectsLoader]; }; [projectsLoaderInitializer registerInitializer]; }
lazy_initializer
will be replaced by __attribute__((constructor)) static void
. The constructor
attribute means that this method will be called earlier than main
(there is a more detailed description here: GCC. Function Attributes ).@property (nonatomic, strong) id loader)
Source: https://habr.com/ru/post/198328/
All Articles