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
Dependency Injection FTW
Search
0xc010d
February 18, 2014
Programming
950
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Dependency Injection FTW
cocoaheadsNL@Utrecht/Atos
0xc010d
February 18, 2014
More Decks by 0xc010d
See All by 0xc010d
Doing CI like a boss
0xc010d
2
420
Reversing 101
0xc010d
6
440
Other Decks in Programming
See All in Programming
速習iPhone Duo対応
yuukiw00w
2
980
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
250
Agents on Rails - Rails at Scale 2026
irinanazarova
0
530
CodeRabbitの効果検証と過ごしてみた3ヶ月
armondando
0
220
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
220
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
なぜCTOを降りてFDEを選んだのか?〜なぜプロダクト企業がFDEで顧客の現場に踏み込むのか〜
gonta
1
190
R8 の設定見直しでアプリサイズ削減
andpad
0
200
SREの越境 / SRE Collaboration
y0hgi
2
300
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.8k
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
400
Featured
See All Featured
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
300
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
320
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
520
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
1k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
710
Building an army of robots
kneath
307
47k
The Pragmatic Product Professional
lauravandoore
37
7.5k
Building AI with AI
inesmontani
PRO
1
1.3k
Transcript
Dependency Injection FTW Ievgen Solodovnykov @0xc010d
I… • work at 2dehands.be • do iOS stuff during
the daylight
Inversion of Control • M. Fowler, 1988 (http://martinfowler.com/bliki/ InversionOfControl.html) •
Don't call us, we'll call you • Dependency Injection is one of possible implementations
Dependency Injection • M. Fowler, 2004 (http://www.martinfowler.com/ articles/injection.html) • Helps
to get rid of hard coupling • Easier unit testing and motivates to write testable code • Improves modularity and reusability
Dependency Injection • Constructor injection • Property injection • Interface
injection + Automatic injection
Constructor injection @interface APIClient : NSObject - (void)loadDataWithCompletionBlock:(void(^)(NSError *))block; @end
! //... ! @implementation ViewController { APIClient *_apiClient; } ! - (instancetype)initWithAPIClient:(APIClient *)apiClient { self = [super init]; _apiClient = apiClient; return self; } ! - (void)viewDidLoad { [super viewDidLoad]; [_apiClient loadDataWithCompletionBlock:^(NSError *) { //... }]; } ! @end
Property injection @interface ViewController : UIViewController ! @property (nonatomic, weak)
APIClient *apiClient; ! @end ! //... ! @implementation ViewController ! - (void)viewDidLoad { [super viewDidLoad]; [self.apiClient loadDataWithCompletionBlock:^(NSError *) { //... }]; } ! @end
Method injection @implementation ViewController ! - (void)viewDidLoad { [super viewDidLoad];
[self loadDataWithAPIClient:[[APIClient alloc] init]]; } ! - (void)loadDataWithAPIClient:(APIClient *)apiClient { [apiClient loadDataWithCompletionBlock:^(NSError *) { //... }]; } ! @end
Automatic injection with BloodMagic • https://github.com/railsware/BloodMagic • Runtime-based • Less
code • Custom initializers • And more…
BMLazy @interface ViewController () <BMLazy> ! @property (nonatomic, weak) APIClient
*apiClient; ! @end ! ! @implementation ViewController ! @dynamic apiClient; ! - (void)viewDidLoad { [super viewDidLoad]; [self.apiClient loadDataWithCompletionBlock:^(NSError *) { //... }]; } ! @end
BMLazy [[APIClient alloc] init] @interface ViewController () <BMLazy> ! @property
(nonatomic, weak) APIClient *apiClient; ! @end ! ! @implementation ViewController ! @dynamic apiClient; ! - (void)viewDidLoad { [super viewDidLoad]; [self.apiClient loadDataWithCompletionBlock:^(NSError *) { //... }]; } ! @end
Custom initializer __attribute__((constructor)) void configureAPIClient(void) { BMInitializer *initializer = [BMInitializer
lazyInitializer]; initializer.propertyClass = [APIClient class]; initializer.initializer = ^id (id sender) { static dispatch_once_t onceToken; static APIClient *client; dispatch_once(&onceToken, ^{ client = [[APIClient alloc] init]; }); return client; }; [initializer registerInitializer]; }
Custom initializer { static dispatch_once_t onceToken; static APIClient *client; dispatch_once(&onceToken,
^{ client = [[APIClient alloc] init]; }); return client; }; @interface ViewController () <BMLazy> ! @property (nonatomic, weak) APIClient *apiClient; ! @end ! ! @implementation ViewController ! @dynamic apiClient; ! - (void)viewDidLoad { [super viewDidLoad]; [self.apiClient loadDataWithCompletionBlock:^(NSError *) { //... }]; } ! @end
Protocol binding @protocol APICLient <NSObject> ! - (void)loadDataWithCompletionBlock:(void (^)(NSError *))completionBlock;
! @end ! //--- ! @interface ProductionAPIClient : NSObject <APICLient> @end ! //--- ! @interface ViewController () <BMLazy> ! @property (nonatomic, weak) id<APICLient> apiClient; ! @end ! //--- ! @dynamic apiClient; ! - (void)viewDidLoad { [super viewDidLoad]; [self.apiClient loadDataWithCompletionBlock:^(NSError *) { //... }]; }
Protocol initializer __attribute__((constructor)) void configureProductionAPIClient(void) { BMInitializer *initializer = [BMInitializer
lazyInitializer]; initializer.protocols = @[ @protocol(APICLient) ]; initializer.initializer = ^id (id sender){ static dispatch_once_t onceToken; static ProductionAPIClient *client; dispatch_once(&onceToken, ^{ client = [[ProductionAPIClient alloc] init]; }); return client; }; [initializer registerInitializer]; } !
Container initializer @interface DemoViewController : ViewController @end ! @interface DemoAPIClient
: NSObject <APICLient> @end ! __attribute__((constructor)) void configureDemoAPIClient(void) { BMInitializer *initializer = [BMInitializer lazyInitializer]; initializer.protocols = @[ @protocol(APICLient) ]; initializer.containerClass = [DemoViewController class]; initializer.initializer = ^id (id sender){ static dispatch_once_t onceToken; static DemoAPIClient *client; dispatch_once(&onceToken, ^{ client = [[DemoAPIClient alloc] init]; }); return client; }; [initializer registerInitializer]; }
Disadvantages • Runtime injecting requires time • Runtime errors •
Requires some intelligence
Alternatives • Typhoon (http://www.typhoonframework.org) • Objection (http://objection-framework.org) • Xider a.k.a
LightMagic (@0xc010d)
Xider vs BloodMagic • Almost as fast as ivar assignment
• Less flexible implementation :(
Unit testing / with BloodMagic
Return value tests • Works fine with functions, often doesn’t
require injection • Call function/method with different parameters • Assert return value
State tests • Might require injection • Setup object •
Call method • Assert object property / other method return value
Interaction tests • Most often requires injection • Setup object
• Call method • Assert other object property / method return value
Demo
Thank you! https://speakerdeck.com/0xc010d/dependency-injection-ftw @0xc010d