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
Pragmatic Core Data
Search
Florian Kugler
January 20, 2016
Programming
8.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Pragmatic Core Data
Florian Kugler
January 20, 2016
More Decks by Florian Kugler
See All by Florian Kugler
AppKit for UIKit developers
floriankugler
0
320
Interactive Animations
floriankugler
1
240
Parallele Programmierung (German!)
floriankugler
0
850
Graphics Performance across iOS Devices
floriankugler
5
1.2k
A Guided Tour Through the SproutCore Jungle
floriankugler
0
1.2k
Other Decks in Programming
See All in Programming
DynamoDBの基礎を振り返りながらベクトル検索機能を理解する
musan
3
250
PyConJP2026_wat_Python × Signal Processing: How to Draw Pictures with Sound Using Spectrogram Art
wat
0
590
go-spidermonkeyでAIエージェントのCode Modeを実装する
syumai
3
1.4k
異なる設計思想のフレームワークを経験して得た学び
amekuhideki
2
860
How I Won Prize Money at a Hackathon Using Codex and Symphony Alpha
yasei_no_otoko
0
130
バグを直したら useEffect が消えた
colorful12
3
770
初めての模倣学習とVLA
natsutan
0
330
Cloudflare is Agents
chimame
0
180
実装をデザインガイドラインに追従させるための取り組み / 260731-dip-mosh-design-system
dachi023
0
7.9k
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
370
AI Readyの正体はデータマネジメントだ メダリオン2.0の最前線
freee
PRO
0
440
VibeCodingからAgenticWorkflowへ
starfish719
0
950
Featured
See All Featured
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
400
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
810
Mind Mapping
helmedeiros
PRO
1
340
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
220
Visualization
eitanlees
152
17k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
45k
From π to Pie charts
rasagy
0
330
Color Theory Basics | Prateek | Gurzu
gurzu
0
440
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Building the Perfect Custom Keyboard
takai
2
850
Transcript
None
Welcome
Pragmatic Core Data CocoaHeads Stockholm, November 9th 2015 @floriankugler
Who has worked with Core Data?
None
Performance & Concurrency
I can't tell you what's the right way
I want to show you how to reason about it
for yourself
Understanding is key
Performance
┌─────────────────────────────────┐ │ Managed Object Context │ │ │ │ ┌───────────┐
┌───────────┐ │ │ │ Managed │ │ Managed │ │ │ │ Object │ │ Object │ │ │ └───────────┘ └───────────┘ │ └─────────────────────────────────┘ ▲ │ ▼ ┌─────────────────────────────────┐ │ Persistent Store Coordinator │ │ │ │ ┌─────────────────────────┐ │ │ │ Persistent Store │ │ │ └─────────────────────────┘ │ │ ▲ │ └────────────────┼────────────────┘ │ ▼ ┌─────────────────────────────────┐ │ SQLite │ └─────────────────────────────────┘
┌─────────────────────────────────┐ │ Managed Object Context │ │ │ │ ┌───────────┐
┌───────────┐ │ │ │ Managed │ │ Managed │ │ Context Tier │ │ Object │ │ Object │ │ │ └───────────┘ └───────────┘ │ └─────────────────────────────────┘ ▲ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ▼ ┌─────────────────────────────────┐ │ Persistent Store Coordinator │ │ │ │ ┌─────────────────────────┐ │ Coordinator Tier │ │ Persistent Store │ │ │ └─────────────────────────┘ │ │ ▲ │ └────────────────┼────────────────┘ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ▼ ┌─────────────────────────────────┐ │ SQLite │ SQLite Tier └─────────────────────────────────┘
The Context Tier → In-memory → Not thread safe →
Lock-free
Working in the Context Tier → Testing for faults →
Accessing properties (on materialized objects) → Traversing to-one relationships (on materialized objects) → Traversing to-many relationships (on materialized relationships)
Working in the Context Tier → Faulting in objects with
objectWithID(_:) → objectRegisteredForID(_:) → Making changes → (Saving a child context)
The Coordinator Tier → In-memory → Thread safe → Potential
lock contention
Working in the Coordinator Tier → Accessing properties (on faults
whose data is in the row cache)
The SQLite Tier → Disk I/O → Thread-safe → Potential
lock contention
Working with the SQLite Tier → Fetch requests → resultType
→ includesPropertyValues → returnsObjectsAsFaults → shouldRefreshRefetchedObjects → includesPendingChanges
Application │ ▲ │ │ │ Object │ Faults ───────────────────────────────┼──────────────────────────────────────┼──────────
Context ▼ │ ┌─────────────────────────────────────────────────────┼─────────┐ │ executeFetchRequest(_:) │ │ │ Accounts for │ │ pending changes │ └───────────────────────────────────────────────────────────────┘ │ ▲ │ │ │ Object Faults ───────────────────────────────┼──────────────────────────────────────┼────────── Coordinator │ │ ┌ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ┐ Store ▼ │ │ ┌────────────────────────────────────────────────────────┐ │ │ executeRequest(_:withContext:) │ │ └────────────────────────────────────────────────────────┘ │ │ ▲ │ │ ┌───────────────┐ │ │ │ │ Row Cache │⾢─────────┤ │ SQL statement └───────────────┘ │ │ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ │ │ ───────────────────────────────┼──────────────────────────────────────┼────────── SQLite │ │ │ Returns raw data │ │ └──────────▶ Executes Query ───────────┘
Working with the SQLite Tier → Saving (root contexts) →
Accessing properties (on faults whose data isn't in the row cache)
Profiling
Core Data Instruments
Core Data Instruments
SQLDebug Output -com.apple.CoreData.SQLDebug 1
SQLDebug Output sql: SELECT t0.Z_ENT, t0.Z_PK, t0.Z_OPT, t0.ZMARKEDFORDELETIONDATE, t0.ZNUMBEROFMOODS, t0.ZNUMERICISO3166CODE,
t0.ZUNIQUENESSDUMMY, t0.ZUPDATEDAT, t0.ZNUMBEROFCOUNTRIES, t0.ZCONTINENT FROM ZGEOGRAPHICREGION t0 WHERE t0.Z_PK = ? annotation: sql connection fetch time: 0.0005s annotation: total fetch execution time: 0.0008s for 1 rows. annotation: fault fulfilled from database for : 0xd000000000100002 <x-coredata://DE6497F9-8B94-420D-81B7-E25B992E28C2/Country/p4>
Best Performance?
Understand Core Data's performance characteristics
Understand Core Data's performance characteristics Reason about your app's behavior
Understand Core Data's performance characteristics Reason about your app's behavior
Make the right choice for your project
Concurrency
The Big Controversy To Nest or not to Nest
The Problem of General Recommendations
Don't Take Our Word for It Reason About It Yourself
Parallel Contexts ┌─────────────────────────┐ ┌─────────────────────────┐ │ Main Queue Context │ │
Private Queue Context │ └────────────▲────────────┘ └────────────▲────────────┘ └─────────────┬─────────────┘ │ ┌──────────────────────────▼──────────────────────────┐ │ Persistent Store Coordinator │ │ │ │ ┌───────────────────────────────────────────────┐ │ │ │ Persistent Store │ │ │ └───────────────────────▲───────────────────────┘ │ └──────────────────────────┼──────────────────────────┘ │ ┌──────────────────────────▼──────────────────────────┐ │ SQLite │ └─────────────────────────────────────────────────────┘
Parallel Contexts Advantages → Requests don't block the other context's
queue → Merging changes can ignore objects that are not used
Parallel Contexts Disadvantages → Saves cause I/O on main queue
Multiple Coordinators ┌──────────────────────────────────┐ ┌──────────────────────────────────┐ │ Main Queue Context │ │
Private Queue Context │ └─────────────────▲────────────────┘ └─────────────────▲────────────────┘ │ │ ┌─────────────────▼────────────────┐ ┌─────────────────▼────────────────┐ │ Persistent Store Coordinator │ │ Persistent Store Coordinator │ │ │ │ │ │ ┌────────────────────────────┐ │ │ ┌────────────────────────────┐ │ │ │ Persistent Store │ │ │ │ Persistent Store │ │ │ └──────────────▲─────────────┘ │ │ └─────────────▲──────────────┘ │ └─────────────────┼────────────────┘ └────────────────┼─────────────────┘ │ │ ┌─────────────────▼────────────────────────────────────▼─────────────────┐ │ SQLite │ └────────────────────────────────────────────────────────────────────────┘
Multiple Coordinators Advantages → Context and coordinator tier are independent
→ Point of contention pushed down to SQLite
Multiple Coordinators Disadvantages → Stacks don't share the row cache
→ Can't share object IDs between stacks (Use URIRepresentation)
Nested Contexts ┌─────────────────────────────────────────────────────┐ │ Private Queue Context │ └──────────────────────────▲──────────────────────────┘ │
┌──────────────────────────▼──────────────────────────┐ │ Main Queue Context │ └──────────────────────────▲──────────────────────────┘ │ ┌──────────────────────────▼──────────────────────────┐ │ Private Queue Context │ └──────────────────────────▲──────────────────────────┘ │ ┌──────────────────────────▼──────────────────────────┐ │ Persistent Store Coordinator │ │ │ │ ┌───────────────────────────────────────────────┐ │ │ │ Persistent Store │ │ │ └───────────────────────▲───────────────────────┘ │ └──────────────────────────┼──────────────────────────┘ │ ┌──────────────────────────▼──────────────────────────┐ │ SQLite │ └─────────────────────────────────────────────────────┘
Nested Contexts Advantages → Save I/O happens on background queue
→ No race conditions to handle when deleting objects
Nested Contexts Disadvantages → Requests in worker contexts block main
queue → Saving a child pushes all changes into the parent → Every save has to go through the main context → No merge policies → Complexity of temporary vs. permanent IDs
Which Stack Should You Use?
Understand the Tradeoffs Reason for Your Project Make a Choice
Save Conflicts
Two-Step Optimistic Locking 1. Between the snapshot and the data
in the persistent store's row cache 2. Between the persistent store's row cache and the data in SQLite
Context-Coordinator Conflict ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ │ Managed Object Context │ │
Managed Object Context │ │ │ │ │ │ ┌─────────────┌────────────┐ │ │ ┌──────────────┌────────────┐ │ │ │ Snapshot V1 │ Foo │ │ │ │ Snapshot V1 │ Foo │ │ │ └─────────────└────────────┘ │ │ └──────────────└────────────┘ │ └─────────────────────────────────┘ └─────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────────┐ │ Persistent Store Coordinator │ │ │ │ ┌────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────┐ │ │ │ │ │ Snapshot V1 │ Row Cache │ │ │ │ └─────────────┘ │ │ │ └────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘
Context-Coordinator Conflict ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ │ Managed Object Context │ │
Managed Object Context │ │ │ │ │ │ ┌─────────────┌────────────┐ │ │ ┌──────────────┌────────────┐ │ │ │ Snapshot V1 │ Foo │ │ │ │ Snapshot V2 │ Foo │ │ │ └─────────────└────────────┘ │ │ └──────────────└────────────┘ │ └─────────────────────────────────┘ └─────────────────────────────────┘ │ ┌───────save──────┘ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Persistent Store Coordinator │ │ │ │ ┌────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────┐ │ │ │ │ │ Snapshot V2 │ Row Cache │ │ │ │ └─────────────┘ │ │ │ └────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘
Context-Coordinator Conflict ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ │ Managed Object Context │ │
Managed Object Context │ │ │ │ │ │ ┌─────────────┌────────────┐ │ │ ┌──────────────┌────────────┐ │ │ │ Snapshot V1 │ Foo │ │ │ │ Snapshot V2 │ Foo │ │ │ └─────────────└────────────┘ │ │ └──────────────└────────────┘ │ └─────────────────────────────────┘ └─────────────────────────────────┘ │ └──────fail!───────┐ ▼ ┌──────────────────────────────────────────────────────────────────────┐ │ Persistent Store Coordinator │ │ │ │ ┌────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────┐ │ │ │ │ │ Snapshot V2 │ Row Cache │ │ │ │ └─────────────┘ │ │ │ └────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘
Coordinator-SQLite Conflict ┌─────────────────────────────────────────────┐ ┌─────────────────────────────────────────────┐ │ Persistent Store Coordinator │ │
Persistent Store Coordinator │ │ │ │ │ │ ┌───────────────────────────────────────┐ │ │ ┌───────────────────────────────────────┐ │ │ │ ┌─────────────┐ │ │ │ │ ┌─────────────┐ │ │ │ │ │ Snapshot V1 │ Row Cache │ │ │ │ │ Snapshot V1 │ Row Cache │ │ │ │ └─────────────┘ │ │ │ │ └─────────────┘ │ │ │ └───────────────────────────────────────┘ │ │ └───────────────────────────────────────┘ │ └─────────────────────────────────────────────┘ └─────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ │ SQLite │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Row V1 │ │ │ └────────────────────────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘
Coordinator-SQLite Conflict ┌─────────────────────────────────────────────┐ ┌─────────────────────────────────────────────┐ │ Persistent Store Coordinator │ │
Persistent Store Coordinator │ │ │ │ │ │ ┌───────────────────────────────────────┐ │ │ ┌───────────────────────────────────────┐ │ │ │ ┌─────────────┐ │ │ │ │ ┌─────────────┐ │ │ │ │ │ Snapshot V1 │ Row Cache │ │ │ │ │ Snapshot V2 │ Row Cache │ │ │ │ └─────────────┘ │ │ │ │ └─────────────┘ │ │ │ └───────────────────────────────────────┘ │ │ └───────────────────────────────────────┘ │ └─────────────────────────────────────────────┘ └─────────────────────────────────────────────┘ │ ┌─────────save──────────┘ ▼ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ │ SQLite │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Row V2 │ │ │ └────────────────────────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘
Coordinator-SQLite Conflict ┌─────────────────────────────────────────────┐ ┌─────────────────────────────────────────────┐ │ Persistent Store Coordinator │ │
Persistent Store Coordinator │ │ │ │ │ │ ┌───────────────────────────────────────┐ │ │ ┌───────────────────────────────────────┐ │ │ │ ┌─────────────┐ │ │ │ │ ┌─────────────┐ │ │ │ │ │ Snapshot V1 │ Row Cache │ │ │ │ │ Snapshot V2 │ Row Cache │ │ │ │ └─────────────┘ │ │ │ │ └─────────────┘ │ │ │ └───────────────────────────────────────┘ │ │ └───────────────────────────────────────┘ │ └─────────────────────────────────────────────┘ └─────────────────────────────────────────────┘ │ └─────────fail!──────────┐ ▼ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ │ SQLite │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Row V2 │ │ │ └────────────────────────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘
Beyond Core Data
Do Not Look for Recipes
Look for Explanations & Think Them Through
Apply This Knowledge to Your Situation
Thank You! @floriankugler