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
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
570
AIだと陥りがちなJakarta EE最新技術への移行時の落とし穴と解決策
tnagao7
0
120
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
12
4.4k
A2UI という光を覗いてみる
satohjohn
1
150
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.7k
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
13
6.2k
Oxcを導入して開発体験が向上した話
yug1224
4
330
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
220
Java × distroless で 軽量なコンテナイメージを / Java on Distroless
contour_gara
0
560
Oxlintのカスタムルールの現況
syumai
6
1.1k
New "Type" system on PicoRuby
pocke
1
1k
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.3k
Featured
See All Featured
The Cost Of JavaScript in 2023
addyosmani
55
10k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
How to build a perfect <img>
jonoalderson
1
5.7k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
330
Unsuck your backbone
ammeep
672
58k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.5k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.4k
A Tale of Four Properties
chriscoyier
163
24k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
330
From π to Pie charts
rasagy
0
220
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