MVC is not sufficient

[[RequestManager sharedInstance] loadResourcesAtPath:@"http://example.com/resources" withDelegate:self]; // or [[DatabaseManager sharedManager] saveResource:resource];

it’s hard to mock or stub Singletons while testing classes that use it

Singleton is a global variable by the nature

from the SRP point of view, object should not control his Singleton behaviour

@interface ViewController : UIViewController @property (nonatomic, strong) RequestManager *requestManager; @end

Dependency Injection

requestManager

RequestManager

ViewController

description of dependencies via macros or string constants

injection occurs only if object is created in a special way (this would not work at least with UIViewController from Storyboard and with UIView from Nib)

injected class should implement some protocol (this would not work with third party libraries)

initialization can’t be placed into a separate module

uses XML to describe dependencies

BloodMagic

@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 @property (nonatomic, strong) ProgressViewService *progressViewService; @property (nonatomic, strong) 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

self.progressViewService

self.resourceLoader

ViewController

BloodMagic and Dependency Injection

+new

BMInitializer *initializer = [BMInitializer lazyInitializer]; initializer.propertyClass = [ProgressViewService class]; initializer.initializer = ^id (id sender){ return [[ProgressViewService alloc] initWithViewController:sender]; }; [initializer registerInitializer];

propertyClass

initializer

nil

+new

sender

containerClass

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

ProjectsViewController

containerClass

NSObject

shared*

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];

Organize initializers

lazy_initializer

// SomeInitializer.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

__attribute__((constructor)) static void

constructor

main

Plans for the near future

implement support of @protocol , e.g.: @property (nonatomic, strong) id loader;

, e.g.: explain how it works

describe how to add new attribute

Every day iOS apps become more cumbersome and bulky, which makes MVC approach not sufficient.We are seeing more and more classes for different purposes: app logic extracts into services, models extends with decorators, view separates into partials and so on. And – what is more important – there are now a lot of dependencies that need to be managed somehow.Singleton is often used to resolve this problem; this is a kind of global variable that everyone can access. How many times have you seen such a code:A lot of projects use this approach, but it entails a few flaws:The first problem is easy to solve – use object property:But this approach entails another issue – someone should ‘fill’ this property.These issues are not unique for Objective-C. If we take a look at more ‘industrial’ languages, e.g. Java or C++, we can find a solution. Widely used approach in Java – Dependency Injection(DI) .DI allows injectingas a singleton in the application, but uses mock object while testing. No one is aware of singleton however – neither, nor– because all this stuff is managed by DI framework.You can find a lot of Objective-C implementations of the Dependency Injection pattern on GitHub, but they have some disadvantages:So, let’s look into another framework (also with its set of disadvantages) – BloodMagic .BloodMagic provides some sort of custom attributes. It’s designed to be extensible, so more features are coming soon. Currently, only one attribute is implemented – Lazy .This attribute allows to initialize objects on demand with a minimum of boilerplate code. Therefore, instead of the following sheets:we can simply write:And that’s it. Bothproperties are created by a call toand. They are released in the same way as a standard properties – afteris deallocated.method is used for object creation here by default. But it also has a capability of writing custom initializers which is a key feature of BMLazy as a DI framework.Creating custom initializer is a bit cumbersome, but works well:– initializer registers for property of this class.– block, which is called to initialize property. If this block is, or initializer is not found for concrete property, then object is created viaclass method.– container class instance.Also, initializer has aproperty, which allows us to describe creation of the same property based on class container. For example:Thus, foranddifferent objects are created. By defaultequals toclass.Initializers help to get rid of variousmethods and hardcoding, described in the beginning:We may have a lot of initializers, so it makes sense to move them into a separate place.Nice solution is to store them in different files and use attributes of a compiler (it’s a normal practice). BloodMagic has also a simple macros that hides this attribute –. We should simply create a source file without header and add it to the compilation phase.Here is an example:will be replaced with. Attributemeans that this method will be called beforefunction (here are details: GCC. Function Attributes ).