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
830
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
370
Reversing 101
0xc010d
6
410
Other Decks in Programming
See All in Programming
プロダクト開発でも使おう 関数のオーバーロード
yoiwamoto
0
160
社内での開発コミュニティ活動とモジュラーモノリス標準化事例のご紹介/xPalette and Introduction of Modular monolith standardization
m4maruyama
1
130
AIコーディング道場勉強会#2 君(エンジニア)たちはどう生きるか
misakiotb
1
240
コード書くの好きな人向けAIコーディング活用tips #orestudy
77web
3
330
エンジニア向け採用ピッチ資料
inusan
0
140
Julia という言語について (FP in Julia « SIDE: F ») for 関数型まつり2025
antimon2
3
970
Cursor AI Agentと伴走する アプリケーションの高速リプレイス
daisuketakeda
1
120
[初登壇@jAZUG]アプリ開発者が気になるGoogleCloud/Azure+wasm/wasi
asaringo
0
130
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
2
210
「ElixirでIoT!!」のこれまでとこれから
takasehideki
0
370
Go Modules: From Basics to Beyond / Go Modulesの基本とその先へ
kuro_kurorrr
0
120
Benchmark
sysong
0
230
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
42
2.7k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
48
2.8k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
8
660
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
130
19k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Java REST API Framework Comparison - PWX 2021
mraible
31
8.6k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
48
5.4k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
2.8k
Rails Girls Zürich Keynote
gr2m
94
14k
How to train your dragon (web standard)
notwaldorf
92
6.1k
Bash Introduction
62gerente
614
210k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.7k
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