Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Depenedency Injection in iOS
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Maciej Oczko
December 17, 2013
Programming
0
72
Depenedency Injection in iOS
Talk given in Łódź and Lublin, Poland, during the Mobile Warsaw on Tour meetups.
Maciej Oczko
December 17, 2013
Tweet
Share
More Decks by Maciej Oczko
See All by Maciej Oczko
Dependency Injection on iOS
maciejoczko
1
130
Working with Legacy Code (Łódź)
maciejoczko
0
56
iOS TDD Workshop (Gdańsk)
maciejoczko
1
82
UICollectionView Basics and Flow Layout
maciejoczko
0
240
UICollectionView Introduction
maciejoczko
0
63
Working With Legacy Code - iOS TDD Workshop
maciejoczko
0
170
Other Decks in Programming
See All in Programming
izumin5210のプロポーザルのネタ探し #tskaigi_msup
izumin5210
1
130
コントリビューターによるDenoのすゝめ / Deno Recommendations by a Contributor
petamoriken
0
200
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
620
MUSUBIXとは
nahisaho
0
140
Unicodeどうしてる? PHPから見たUnicode対応と他言語での対応についてのお伺い
youkidearitai
PRO
1
2.6k
CSC307 Lecture 09
javiergs
PRO
1
840
カスタマーサクセス業務を変革したヘルススコアの実現と学び
_hummer0724
0
720
QAフローを最適化し、品質水準を満たしながらリリースまでの期間を最短化する #RSGT2026
shibayu36
2
4.4k
AIフル活用時代だからこそ学んでおきたい働き方の心得
shinoyu
0
140
2026年 エンジニアリング自己学習法
yumechi
0
140
360° Signals in Angular: Signal Forms with SignalStore & Resources @ngLondon 01/2026
manfredsteyer
PRO
0
130
AI時代の認知負荷との向き合い方
optfit
0
160
Featured
See All Featured
Are puppies a ranking factor?
jonoalderson
1
2.7k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
1
1.4k
The Language of Interfaces
destraynor
162
26k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
120
Producing Creativity
orderedlist
PRO
348
40k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.1k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.2k
エンジニアに許された特別な時間の終わり
watany
106
230k
Faster Mobile Websites
deanohume
310
31k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
290
Evolving SEO for Evolving Search Engines
ryanjones
0
130
Building a Modern Day E-commerce SEO Strategy
aleyda
45
8.7k
Transcript
What about DI on iOS?
Who am I? Software Engineer at Polidea Maciej Oczko @maciejoczko
What about DI on iOS?
What about DI on iOS?
Aims • To talk about what DI is • To
encourage you to proceed with DI pattern • To make your coding easier with Objection or Typhoon
What is it all about? You always deal with dependency
management somehow…
What is it all about? You always deal with dependency
management somehow… …but not necessarily in a good way.
Example 1 - (id)init { self = [super init]; if
(self) { _weatherClient = [[MYWeatherClient alloc] initWithY:y andX:x]; } return self; }
Example 1 - (id)init { self = [super init]; if
(self) { _weatherClient = [[MYWeatherClient alloc] initWithY:y andX:x]; } return self; }
Example 2 - (id)init { self = [super init]; if
(self) { _weatherClient = [MYWeatherClient sharedInstance]; } return self; }
Example 3 - (id)initWithWeatherClient:(id <MYWeatherClientProtocol>)client { self = [super init];
if (self) { _weatherClient = client; } return self; }
Example 3 - (id)initWithWeatherClient:(id <MYWeatherClientProtocol>)client { self = [super init];
if (self) { _weatherClient = client; } return self; } DI
Why DI? Pros • Classes are easier to test (or
even possible) • It promotes separation of concerns (single responsibility principle) • Open-closed principle • Makes app maintenance easier • Makes introducing new features less painful
Example 1 << 2 describe(@"Super spec", ^{ it(@"should always pass",
^{ ! ! ! ! ! ! ! ! ! ! ! ! ! ! }); });
Example 1 << 2 describe(@"Super spec", ^{ it(@"should always pass",
^{ ! ! ! ! ! ! ! ! ! ! ! ! ! ! }); }); id <MYAPIAccessorProtocol> accessor = [KWMock mockForProtocol:@protocol(MYAPIAccessorProtocol)]; ! id <MYCacheManagerProtocol> cache = [MYCacheManager new];
Example 1 << 2 describe(@"Super spec", ^{ it(@"should always pass",
^{ ! ! ! ! ! ! ! ! ! ! ! ! ! ! }); }); id <MYAPIAccessorProtocol> accessor = [KWMock mockForProtocol:@protocol(MYAPIAccessorProtocol)]; ! id <MYCacheManagerProtocol> cache = [MYCacheManager new]; . . . ! MYWeatherClient *client = [[MYWeatherClient alloc] initWithX:accessor andY:cache];
Example 1 << 2 describe(@"Super spec", ^{ it(@"should always pass",
^{ ! ! ! ! ! ! ! ! ! ! ! ! ! ! }); }); id <MYAPIAccessorProtocol> accessor = [KWMock mockForProtocol:@protocol(MYAPIAccessorProtocol)]; ! id <MYCacheManagerProtocol> cache = [MYCacheManager new]; . . . ! MYWeatherClient *client = [[MYWeatherClient alloc] initWithX:accessor andY:cache]; [client getWeather]; [[[client.weatherItems should] have:4] elements];
Cons • Life cycle management • Objects’ creation get more
complex • Sometimes more code
Problems? ImageManager CoreDataStorage APIAccessor Cache UserManager ImageValidator FileManager TaskRunner
Problems? - (id)initWithImageValidator:(id <MYImageValidatorProtocol>)imageValidator cacheManager:(id <MYCacheProtocol>)cacheManager userManager:(id <MYUserManagerProtocol>)userManager apiAccessor:(id <MYAPIProtocol>)apiAccessor
coreDataManager:(id <MYCoreDataProtocol>)coreDataManager { self = [super init]; if (self) { ... } return self; } id <MYFileManagerProtocol> fileManager = [[MYFileManager alloc] init]; id <MYImageValidatorProtocol> imageValidator = [[MYImageValidator alloc] initWithFileManager:fileManager]; ! id <MYCacheProtocol> cacheManager = [[MYCacheManager alloc] initWithFileManager:fileManager]; id <MYCoreDataProtocol> coreDataManager = [[MYCoreDataManager alloc] init]; ! id <MYAPIProtocol> apiAccessor = [[MYAPIAccessor alloc] initWith:...]; ... MYImageManager *imageManager = [[MYImageManager alloc] initWithImageValidator:imageValidator cacheManager:cacheManager userManager:userManager apiAccessor:apiAccessor coreDataManager:coreDataManager];
None
Frameworks
Objection
• ‘Annotation’ based DI • Initializer support • Proporties auto-wiring
• Lazily instantiated dependencies • Custom providers • Class bindings • Protocol bindings • Instance bindings • Life cycle management • Cyclic dependencies
How it works, quickly Injector id obj = [injector getObject:@protocol(FancyProtocol)];
Module [self bindProtocol:@protocol(FancyProtocol) toClass:[MYFancy class]];
Initializer @implementation MYObject ! objection_initializer_sel(@selector(initWithClient:)) ! - (id)initWithClient:(id <MYClientProtocol>)client {
self = [super init]; if (self) { _client = client; } return self; } ! @end ! ! ! ! !
Initializer @implementation ! objection_initializer_sel ! - ( _client } !
@end ! ! ! ! ! id obj = [injector getObject:[MYObject class] argumentList:@[ client ]];
Properties @interface MYObject @property(nonatomic, readonly) id <MYClientProtocol> client; @property(nonatomic, readonly)
id <MYAPIProtocol> apiAccessor; @end ! @implementation MYObject ! objection_requires_sel(@selector(client), @selector(apiAccessor)) ! - (id)init { self = [super init]; if (self) { return self; } ! - (void)awakeFromObjection { } ! @end ! ! !
Properties @interface @property @property @end ! @implementation ! objection_requires_sel !
- (id } ! - (void ! @end ! ! ! id obj = [injector getObject:[MYObject class]];
Pros & Cons • Easy to use • Fairly simple
• Configuration in place • Invasive • Properties driven! • A few defects
Typhoon
• All Objection features • No macros or XML required
but both supported • Any order of dependencies • Supports configuration management • Supports injection of view controllers and storyboard integration
How it works, quickly Component Factory Assembly MYObject *object =
[componentFactory componentForType:[MYObject class]; - (id)myObject { return [TyphoonDefinition withClass:[MYObject Class]]; }
Assembly ! @interface MYAssemby : TyphoonAssembly ! @implementation MYAssembly !
- (id)imageManager { return [TyphoonDefinition withClass:[MYImageManager class]
Assembly ! @interface MYAssemby : TyphoonAssembly ! @implementation MYAssembly !
- (id)imageManager { return [TyphoonDefinition withClass:[MYImageManager class] initialization:^(TyphoonInitializer* initializer) { ! initializer.selector = @selector(initWithClient:); [initializer injectWithDefinition:[self defaultClient]]; ! }
Assembly ! @interface MYAssemby : TyphoonAssembly ! @implementation MYAssembly !
- (id)imageManager { return [TyphoonDefinition withClass:[MYImageManager class] initialization:^(TyphoonInitializer* initializer) { ! initializer.selector = @selector(initWithClient:); [initializer injectWithDefinition:[self defaultClient]]; ! } properties:^(TyphoonDefinition* definition) { ! [definition injectProperty:@selector(api) withDefinition:[self api]]; [definition injectProperty:@selector(task) withValueAsText:@"${tasks.first}"]; ! [definition setAfterPropertyInjection:@selector(configureBeforeUse)]; [definition setScope:TyphoonScopeSingleton]; }]; }
Pros & Cons • One configuration place • Configuration in
place • Not invasive • Lots of features • More complicated code base • Clarity
None
None
Summary • DI makes testing a lot easier • DI
improves your code effectiveness • DI makes your classes cleaner and more reusable • DI frameworks usage makes your life easier
Thanks!
[email protected]
@maciejoczko