27
Dependency Injection в iOS Дугнист Владислав

CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Embed Size (px)

Citation preview

Page 1: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Dependency Injection в iOS

Дугнист Владислав

Page 2: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

План

• Что такое зависимости?

• Что такое внедрение зависимостей (DI)?

• Какие плюсы мы получаем при использовании DI?

• Почему я выбрал Blood Magic.

2

Page 3: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Зависимости

View Controller

3

Page 4: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Зависимости

View Controller

Service

Data

3

Page 5: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Зависимости

- (void)viewDidLoad { [super viewDidLoad]; __weak typeof(self) wSelf = self; [??? citiesWeatherWithCallback:^(NSArray *array, NSError *error) { wSelf.cities = array; [wSelf.tableView reloadData]; }]; }

4

Page 6: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Зависимости

- (void)viewDidLoad { [super viewDidLoad]; __weak typeof(self) wSelf = self; [??? citiesWeatherWithCallback:^(NSArray *array, NSError *error) { wSelf.cities = array; [wSelf.tableView reloadData]; }]; }

Зависимость

4

Page 7: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Зависимости

Singleton решение: - (void)viewDidLoad { [super viewDidLoad]; __weak typeof(self) wSelf = self; [[WFCOpenWeatherService sharedInstance] citiesWeatherWithCallback:^(NSArray *array, NSError *error) { wSelf.cities = array; [wSelf.tableView reloadData]; }]; }

5

Page 8: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Зависимости

Singleton решение: - (void)viewDidLoad { [super viewDidLoad]; __weak typeof(self) wSelf = self; [[WFCOpenWeatherService sharedInstance] citiesWeatherWithCallback:^(NSArray *array, NSError *error) { wSelf.cities = array; [wSelf.tableView reloadData]; }]; }

Неявная зависимость

5

Page 9: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Признак неявных зависимостей

// WFCViewController.h

@interface WFCViewController : UIViewController

@end

6

Page 10: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Inversion of control// WFCViewController.h

@interface WFCViewController : UIViewController

@property (nonatomic) id <WFCWeatherServiceProtocol> weatherService;

@end

// WFCViewController.m

- (void)viewDidLoad { [super viewDidLoad]; __weak typeof(self) wSelf = self; [_weatherService citiesWeatherWithCallback:^(NSArray *array, NSError *error) { wSelf.cities = array; [wSelf.tableView reloadData]; }]; }

7

Page 11: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Чем полезен IoC?

• Повышает читаемость кода.

• Позволяет выставлять сервисы с заглушками в отладочной версии.

• Упрощает тестирование.

Page 12: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Демо

9

Page 13: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Blood Magic

• github: https://github.com/railsware/BloodMagic

• Podfile: pod 'BloodMagic/Injectable', :git => 'https://github.com/railsware/BloodMagic.git'

Page 14: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Blood Magic

BMInitializer *weatherServiceInitializer = [BMInitializer injectableInitializer];

weatherServiceInitializer.containerClass = [WFCViewController class];

weatherServiceInitializer.protocols =

@[@protocol(WFCWeatherServiceProtocol)];

weatherServiceInitializer.initializer = ^id (id sender) { return [WFCLocalWeatherService new]; }; [weatherServiceInitializer registerInitializer];

Page 15: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Blood Magic (синтаксис)

@interface BMInitializer : NSObject

@property (nonatomic, strong) Class propertyClass; @property (nonatomic, strong) Class containerClass; @property (nonatomic, strong) NSArray *protocols;

@property (nonatomic, copy) magic_initializer_t initializer;

- (void)registerInitializer;

@end

Page 16: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Blood Magic

// WFCViewController.h

@interface WFCViewController : UIViewController <BMInjectable>

@property (nonatomic) id <WFCWeatherServiceProtocol> weatherService;

@end

// WFCViewController.m

@dynamic weatherService;

Page 17: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Демо 2

Page 18: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Другие DI-фреймворки

Page 19: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Typhoon

• http://typhoonframework.org

• github: https://github.com/appsquickly/Typhoon

• Серия статей на хабре: http://habrahabr.ru/company/rambler-co/blog/258325/

• Доклад Rambler&Co: http://www.youtube.com/watch?v=LO59z3fjc9k

Page 20: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Typhoon

• Конфигурация зависимостей на уровне assembly.

• Auto-inject.

Page 21: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Typhoon

Удобные аннотации:

@interface WFCViewController : UIViewController

@property (nonatomic) InjectedProtocol(WFCWeatherServiceProtocol) weatherService;

@end

Page 22: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Typhoon@implementation WFCAssembly

- (id <WFCWeatherServiceProtocol>)defaultWeatherService { return [TyphoonDefinition withClass:[WFCLocalWeatherService class] configuration:^(TyphoonDefinition *definition) { definition.scope = TyphoonScopeSingleton; }]; }

@end

typedef NS_ENUM(NSInteger, TyphoonScope) { TyphoonScopeObjectGraph, TyphoonScopePrototype, TyphoonScopeSingleton, TyphoonScopeLazySingleton, TyphoonScopeWeakSingleton, };

Page 23: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Typhoon+ удобные аннотации

+ поддержка scope

+ больше community

- большие накладные расходы при работе с assembly

- нет возможности выставить условием containerClass при auto inject’ах

Page 24: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Objection

• http://objection-framework.org

• github: https://github.com/atomicobject/objection

Page 25: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Objection

@interface Car : NSObject { Engine *engine; Brakes *brakes; BOOL awake; }

// Will be filled in by objection @property(nonatomic, strong) Engine *engine; // Will be filled in by objection @property(nonatomic, strong) Brakes *brakes; @property(nonatomic) BOOL awake;

@implementation Car objection_requires(@"engine", @"brakes") @synthesize engine, brakes, awake; @end

Page 26: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

Objection+ поддержка scope

+ второй по популярности после typhoon

- синтаксис

- отсутствие аннотаций

- нет возможности выставить условием containerClass при inject’ах

Page 27: CocoaHeads Moscow. Владислав Дугнист. «Dependency Injection с Blood Magic»

The end

cocoaheads slack: @dv

other: /vdugnist