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
Dependency Injection FTW
Search
0xc010d
February 18, 2014
Programming
2
890
Dependency Injection FTW
cocoaheadsNL@Utrecht/Atos
0xc010d
February 18, 2014
Tweet
Share
More Decks by 0xc010d
See All by 0xc010d
Doing CI like a boss
0xc010d
2
390
Reversing 101
0xc010d
6
410
Other Decks in Programming
See All in Programming
FOSDEM 2026: STUNMESH-go: Building P2P WireGuard Mesh Without Self-Hosted Infrastructure
tjjh89017
0
160
Implementation Patterns
denyspoltorak
0
280
Automatic Grammar Agreementと Markdown Extended Attributes について
kishikawakatsumi
0
180
2026年 エンジニアリング自己学習法
yumechi
0
130
インターン生でもAuth0で認証基盤刷新が出来るのか
taku271
0
190
AIエージェント、”どう作るか”で差は出るか? / AI Agents: Does the "How" Make a Difference?
rkaga
4
2k
余白を設計しフロントエンド開発を 加速させる
tsukuha
7
2.1k
humanlayerのブログから学ぶ、良いCLAUDE.mdの書き方
tsukamoto1783
0
190
KIKI_MBSD Cybersecurity Challenges 2025
ikema
0
1.3k
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
2.3k
AI & Enginnering
codelynx
0
110
Architectural Extensions
denyspoltorak
0
280
Featured
See All Featured
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
62
49k
Ethics towards AI in product and experience design
skipperchong
2
190
Measuring & Analyzing Core Web Vitals
bluesmoon
9
750
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
140
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
98
How to Think Like a Performance Engineer
csswizardry
28
2.4k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
450
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
57
50k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
180
Thoughts on Productivity
jonyablonski
74
5k
YesSQL, Process and Tooling at Scale
rocio
174
15k
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