2. Dependency Injection в iOS
Об авторе
• Twitter: @igrekde
• GitHub: github.com/igrekde
• Блог: etolstoy.ru/blog
3. Dependency Injection в iOS
Содержание
• Принцип инверсии зависимостей
• Паттерны Dependency Injection
• DI в проектах Rambler&Co
• Typhoon Framework
5. Dependency Injection в iOS
SOLID
• S – The Single Responsibility Principle
• O – The Open-Closed Principle
• L – The Liskov Substitution Principle
• I – Interface Segregation Principle
• D – The Dependency Inversion Principle
6. Dependency Injection в iOS
–Роберт Мартин, “Принципы, паттерны и методики гибкой разработки”
Модули верхнего уровня не должны зависеть от модулей
нижнего уровня. И те и другие должны зависеть от
абстракций.
Абстракции не должны зависеть от деталей. Детали должны
зависеть от абстракций.
19. Dependency Injection в iOS
Service Locator
@interface MessageViewController
- (instancetype)initWithMessageService:(id <MessageService>)messageService
attachmentService:(id <AttachmentService>)attachmentService
renderer:(id <MessageRenderer>)renderer;
@end
Было:
20. Dependency Injection в iOS
Service Locator
@interface MessageViewController
- (instancetype)initWithServiceLocator:(id <ServiceLocator>)locator;
@end
Стало:
21. Dependency Injection в iOS
Service Locator
Плюсы:
• Быстро реализуется
• Централизованное управление зависимостями
22. Dependency Injection в iOS
Service Locator
Минусы:
• Приводит к неявным зависимостям
• Видимость хорошего дизайна
• Усложняет тестирование
23. Dependency Injection в iOS
DI container
• Не используется в коде напрямую
• Зависимости всех классов – явные
• Никто не заботится о создании зависимостей
25. Dependency Injection в iOS
Афиша Рестораны
@interface ARModalTableViewController : UIViewController <ARTableViewModelDelegate>
- (instancetype)initWithTableViewModel:(id<ARTableViewModel>)tableViewModel;
@end
Initializer Injection для UIViewController:
26. Dependency Injection в iOS
Афиша Рестораны
@protocol ARStoredListManager <NSObject>
- (void)setStorage:(id<ARLocalStorage>)storage;
@end
Установка зависимости через Setter:
27. Dependency Injection в iOS
Рамблер.Новости
@interface RDNDrawerRouterImplementation ()
……
destinationController.storyboardFactory = sourceController.storyboardFactory;
destinationController.router = [RDNFeedRouterImplementation new];
#warning Заменить fake-адаптер на боевой
destinationController.feedServiceAdapter = [RDNFakeServiceAdapterAssembly
fakeFeedDataServiceAdapterWithTopicIdentifier:topicIdentifier];
……
@end
Почти DI-контейнер:
28. Dependency Injection в iOS
Рамблер.WE
@interface RCIAuthorizationPresenter : NSObject <RCIAuthorizationViewOutput,
RCIAuthorizationInteractorOutput, RCIAuthorizationRouterOutput>
@property (strong, nonatomic) id <RCIAuthorizationViewInput> view;
@property (strong, nonatomic) id <RCIAuthorizationInteractorInput> interactor;
@property (strong, nonatomic) id <RCIAuthorizationRouter> router;
@end
Property Injection в модуле VIPER:
29. Dependency Injection в iOS
Рамблер.Почта
@interface RCMFolderSynchronizationOperation : RCMAsyncOperation<RCMRestartableOperation>
- (instancetype)initWithClient:(id <RCMRPCClient>)client
validator:(id <RCMValidator>)validator
mapper:(id <RCMMapper>)mapper;
@end
Создание операции с Initializer Injection:
33. Dependency Injection в iOS
Typhoon Framework
1.209
124
24 open/260 closed
0 open/60 closed
questions: 246
Последнее обновление: 09.05.15
34. Dependency Injection в iOS
Typhoon Framework
• Полностью нативен
• Поддерживает модульность
• Полная интеграция со Storyboard
• Initializer, Property и Method Injection
• Поддерживает circular dependencies
• Всего 3000 строчек кода
35. Dependency Injection в iOS
Интеграция с проектом
@interface RIAssembly : TyphoonAssembly
- (RIAppDelegate *)appDelegate;
@end
Создаем свою Assembly:
36. Dependency Injection в iOS
Интеграция с проектом
@implementation RIAssembly
- (RIAppDelegate *)appDelegate {
return [TyphoonDefinition withClass:[RIAppDelegate class] configuration:^(TyphoonDefinition *definition) {
[definition injectProperty:@selector(startUpConfigurator) with:[self startUpConfigurator]];
}
}
- (id <RIStartUpConfigurator>)startUpConfigurator {
return [TyphoonDefinition withClass:[RIStartUpConfiguratorBase class]];
}
@end
46. Dependency Injection в iOS
Жизненный цикл
1. main.m
2. Создание UIApplication
3. Создание UIAppDelegate
4. Вызов [UIApplication setDelegate] -> Встраивается Typhoon
5. Вызов [UIAppDelegate applicationDidFinishLaunching]
47. Dependency Injection в iOS
TyphoonAssembly
Активация:
1. Автоматическая при наличии ключа в Info.plist
2. Ручная с использованием [TyphoonAssembly activate].
48. Dependency Injection в iOS
TyphoonAssembly
Активация:
1. Автоматическая при наличии ключа в Info.plist
2. Ручная с использованием [TyphoonAssembly activate].
65. Dependency Injection в iOS
Autowire
Плюсы:
• Быстро реализуется
• Меньше кода в фабриках
Минусы:
• Сильная привязка к Typhoon
• Архитектура приложения не читается в фабриках
73. Dependency Injection в iOS
Мифы
• Высокий порог вхождения
• Очень сложный дебаггинг
• Если Typhoon перестанут поддерживать, из проекта его не
выпилить
• Но… там же свиззлинг!
• Зачем мне Typhoon, когда я могу написать свой велосипед?
74. Dependency Injection в iOS
Рекомендации
• Разбивайте свои фабрики не только вертикально, но и
горизонтально
• Разбивайте фабрики по модулям заранее
• Покрывайте фабрики тестами
79. Dependency Injection в iOS
Objection
Плюсы:
• Легко и просто бьется на модули
• Легковесная
• Простая для освоения
80. Dependency Injection в iOS
Objection
Минусы:
• Все зависимости назначаются практически вручную
• Слишком сильная интеграция с кодом приложения
• Всего два вида объектов: прототип и синглтон
81. Dependency Injection в iOS
BloodMagic
216
30
2 open/6 closed
0 open/12 closed
By AlexDenisov
https://github.com/railsware/BloodMagic
Последнее обновление: 12.05.15
83. Dependency Injection в iOS
BloodMagic
Плюсы:
• Еще более легковесная библиотека
Минусы:
• Не позволяет создавать и управлять графами объектов
• Нет никаких плюшек DI-фреймворков