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 on iOS
Search
Maciej Oczko
June 22, 2015
Programming
130
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Dependency Injection on iOS
Given at Mobile Warsaw meet up.
Maciej Oczko
June 22, 2015
More Decks by Maciej Oczko
See All by Maciej Oczko
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
64
Working With Legacy Code - iOS TDD Workshop
maciejoczko
0
170
Depenedency Injection in iOS
maciejoczko
0
73
Other Decks in Programming
See All in Programming
App Intentsのビルドプロセスを支える技術
kntkymt
0
400
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
250
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
350
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
160
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
170
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
200
数年滞っていたダークモード対応をおよそ2週間で完了させる
chigichan24
0
730
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
7.5k
AI活用は、個人から組織へ|マルチプレイヤーエージェントハーネス「QM」の社内活用事例 / AI use is moving from individuals to orgs
rkaga
1
120
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
470
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
1
150
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
3k
Featured
See All Featured
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.9k
Docker and Python
trallard
47
4.2k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
Unsuck your backbone
ammeep
672
58k
Git: the NoSQL Database
bkeepers
PRO
432
67k
A designer walks into a library…
pauljervisheath
211
25k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
530
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
370
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
870
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
550
Transcript
Dependency Injection on iOS #iOSDI
@MaciejOczko #iOSDI
Why DIY Frameworks #iOSDI
! #iOSDI
Tests #iOSDI
We all ❤ TDD #iOSDI
! #iOSDI
! #iOSDI
⏰ #iOSDI
Code changes ! #iOSDI
Mind changes ! #iOSDI
Design changes ! #iOSDI
DI is the ! pattern while reacting to a change
#iOSDI
Trust Driven Development? #iOSDI
! #iOSDI
Why #iOSDI
Example 1 class MusicAdvisor: NSObject { - (instancetype)init { self
= [super init]; if (self) { _albumProvider = [[AlbumProvider alloc] initWithMusicService:[MusicService new] artistsProvider:[ArtistsProvider new]]; } } } #iOSDI
! #iOSDI
Example 2 class MusicAdvisor: NSObject { - (instancetype)init { self
= [super init]; if (self) { self.musicService = [MusicService new]; self.artistsProvider = [ArtistsProvider new]; _albumProvider = [[AlbumProvider alloc] initWithMusicService:self.musicService artistsProvider:self.artistsProvider]; } } } #iOSDI
! #iOSDI
Example 3 class MusicAdvisor: NSObject { - (instancetype)init { self
= [super init]; if (self) { _albumProvider = [AlbumProvider sharedInstance]; } } } #iOSDI
Example 3 continues... class MusicAdvisor: NSObject { - (Soundtrack *)theBestSoundtrackEver
{ NSArray<Album *> *allAlbums = [[AlbumProvider sharedInstance] allAlbums]; ... return [Soundtrack withSongs: bestSongsEver]; } } #iOSDI
! #iOSDI
! #iOSDI
Solution class MusicAdvisor: NSObject { - (instancetype)initWithAlbumProvider:(id <AlbumProvider>)albumProvider { self
= [super init]; if (self) { _albumProvider = albumProvider; } } } #iOSDI
Solution continues... 1 class MusicAdvisor: NSObject { - (instancetype)initWithAlbumProvider:(id <AlbumProvider>)albumProvider
{ self = [super init]; if (self) { _albumProvider = albumProvider; } } } 2 id <AlbumProvider> albumProvider = [AlbumProvider new]; MusicAdvisor *musicAdvisor = [MusicAdvisor new]; musicAdviser.albumProvider = albumProvider; #iOSDI
Initializer approach » Immutability » Clear interface #iOSDI
! #iOSDI
Benefits » Easier to test classes » Tight-coupling removed »
Promotes composition and separation of concepts #iOSDI
DIY #iOSDI
Strategies 1.Pass objects around 2.Develop application context #iOSDI
App context usage @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ self.window.rootViewController = [self.appContext rootViewController]; [self.window makeKeyAndVisible]; return YES; } ... @end #iOSDI
App context implementation @implementation AppContext ... - (AlbumsDataSource *)albumsDataSourceWithHTTPClient:(id <HTTPClient>)httpClient
{ return [[AlbumsDataSource alloc] initWithHTTPClient:httpClient]; } - (AlbumsViewController *)rootViewController { AlbumsDataSource *dataSource = [self albumsDataSourceWithHTTPClient:[self httpClient]]; AlbumsViewController *albumsViewController = [[AlbumsViewController alloc] initWithDataSource:dataSource]; albumsViewController.appContext = self; return albumsViewController; } @end #iOSDI
App context usage @implementation AlbumsViewController ... - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath { ... AlbumDetailsViewController *advc = [self.appContext albumDetailsViewContorllerWithAlbum:album]; [self presentViewController:advc animated:YES completion:nil]; } @end #iOSDI
! #iOSDI
Frame works #iOSDI
Objection Typhoon #iOSDI
Objection » Lightweight » "Annotation" Based Dependency Injection » Bindings
» Lazily instantiates dependencies » Eager Singletons » Initializer Support #iOSDI
Key concepts » Injector » Module #iOSDI
Usage @interface MusicAdvisor @property(nonatomic, strong, readonly) AlbumProvider *albumProvider; @end @implementation
MusicAdvisor objection_requires_sel(@selector(albumProvider)) - (void)awakeFromObjection { // Initialize with injected properties } @end #iOSDI
Usage JSObjectionInjector *injector = [JSObjection createInjector]; MusicAdvisor *musicAdvisor = [injection
getObject:[MusicAdvisor class]]; #iOSDI
Advanced usage @interface MyModule : JSObjectionModule @end @implementation MyModule -
(void)configure { [self bindClass:[AlbumProvider class] toProtocol:@protocol(AlbumProvider)]; [self bindProvider:[MusicAdvisorProvider new] toClass:[MusicAdvisor class]]; [self bindBlock:^(JSObjectionInjector *context) { // Manual creation return soundTrack; } toClass:[Soundtrack class]]; [self bindClass:[MusicAdvisor class] inScope:JSObjectionScopeSingleton]; } @end #iOSDI
Advanced usage JSObjectionInjector *injector = [JSObjection createInjector:[MyModule new]]; MusicAdvisor *musicAdvisor
= [injection getObject:[MusicAdvisor class]]; #iOSDI
Try it » Lightweight » Simple » Flexbile #iOSDI
... or not? » Lightweight » Not Swift friendly »
Property injection approach » Invasive #iOSDI
Typhoon » All Objection's features » Life-cycle management » Circular
dependecies support » Refactorable » Storyboard integration » Swift support #iOSDI
Key concepts » Assembly » Definition #iOSDI
Usage class MusicAssembly: TyphoonAssembly { public dynamic func albumProvider() ->
AnyObject { return TyphoonDefinition.withClass(AlbumProvider.self) } ... } #iOSDI
Usage let assembly = MusicAssembly().activate() let albumProvider = assembly.albumProvider() as!
AlbumProvider #iOSDI
Usage class MusicAssembly: TyphoonAssembly { public dynamic func albumProvider() ->
AnyObject { return TyphoonDefinition.withClass(AlbumProvider.self) } public dynamic func musicAdvisor() -> AnyObject { return TyphoonDefinition.withClass(MusicAdvisor.self) { definition in definition.useInitializer("initWithAlbumProvider:") { initializer in initializer.injectParameterWith(self.albumProvider()) } definition.injectProperty("soundTrackComposer", self.soundtrackComposer()) definition.injectProperty("assembly") // definition.scope = TyphoonScope.Singleton } } } #iOSDI
Usage let assembly = MusicAssembly().activate() let musicAdvisor = assembly.musicAdvisor() as!
MusicAdvisor #iOSDI
Advanced usage public class MusicAssembly: TyphoonAssembly { public var themesAssembly:
ThemesAssembly! public dynamic func musicAdvisor(albumProvier: AlbumProvider) -> AnyObject { return TyphoonDefinition.withClass(MusicAdvisor.self) { definition in definition.useInitializer("initWithAlbumProvider:themesComposer:") { initializer in initializer.injectParameterWith(albumProvider) initializer.injectParameterWith(self.themesAssembly.defaultComposer) } } } public dynamic func appDelegate() -> AnyObject { return TyphoonDefinition.withClass(AppDelegate.self) { (definition) in definition.injectProperty("musicAdvisor", with: self.musicAdvisor()) definition.injectProperty("rootViewController", with: RootViewController()) definition.injectProperty("assembly") } } ... } #iOSDI
Advanced usage @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var musicAdvisor:
MusicAdvisor? var rootViewController: RootViewController? var assemby: MusicAssembly? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Actiation via Info.plist - InitialTyphoonAssemblies self.window?.rootViewController = self.rootViewController self.musicAdvisor?.adviseMe() { [unowned self] music in let musicPlayer = self.assembly.musicPlayer(music: music) ... } return true } } #iOSDI
Cons » May seem overwhelming » Complex » Learning curve
#iOSDI
Pros » Configurable » Promotes initializer-injection » Non-invasive » Supports
testing » Supports Swift #iOSDI
Recap » Dependency injection is powerful pattern » To learn
it, build your own injection mechanism » There are frameworks to help you » Objection » Typhoon #iOSDI
Thanks! @MaciejOczko #iOSDI