Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Depenedency Injection in iOS
Search
Maciej Oczko
December 17, 2013
Programming
73
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Depenedency Injection in iOS
Talk given in Łódź and Lublin, Poland, during the Mobile Warsaw on Tour meetups.
Maciej Oczko
December 17, 2013
More Decks by Maciej Oczko
See All by Maciej Oczko
Dependency Injection on iOS
maciejoczko
1
130
Working with Legacy Code (Łódź)
maciejoczko
0
59
iOS TDD Workshop (Gdańsk)
maciejoczko
1
85
UICollectionView Basics and Flow Layout
maciejoczko
0
250
UICollectionView Introduction
maciejoczko
0
70
Working With Legacy Code - iOS TDD Workshop
maciejoczko
0
170
Other Decks in Programming
See All in Programming
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
1k
IBM Bob Dojo #1 仕様駆動開発入門
oniak3ibm
PRO
0
390
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
1.1k
残高管理から台帳サービスへの進化
artoy
1
200
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
610
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
750
Kotlinの15年とServer-Side Kotlin
n_takehata
1
150
Optunaを作ったときにやりたかったこと、その後 (2026/10/16, Optuna Meetup #3)
iwiwi
1
430
Event is what happens
moro
2
770
3回つくってわかった、 定期実行ジョブ基盤の本質情報
takai
0
450
複雑なUIコンポーネントとの ⻑い付き合い⽅:波及するバグからテスト戦略を経て、安全な再設計へ
mixplace
0
410
AmebaブログはKMPから卒業します
kmars0605
0
180
Featured
See All Featured
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.2k
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
870
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.3k
Optimizing for Happiness
mojombo
378
71k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.9k
Site-Speed That Sticks
csswizardry
13
1.6k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.5k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
450
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
570
Building an army of robots
kneath
307
47k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
600
Navigating Team Friction
lara
192
16k
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