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
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
4.1k
torikago - Ruby::Boxで照らすモジュラモノリスの実行境界
se4weed
1
350
PHP Application における Kubernetes 内 gRPC 通信
ganchiku
0
590
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.4k
【QA Test Talk Vol.8】AI-DLC による Whole Team Approach の加速
pkshadeck
PRO
0
120
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
600
テーブルをDELETEした
yuzneri
0
140
FDEが実現するAI駆動経営の現在地
gonta
2
270
React本体のコードリーディング
high_g_engineer
1
140
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.9k
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
210
仕様駆動開発へのトライを機に チームに適合する手法を模索し続けている話
freee
PRO
0
450
Featured
See All Featured
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
480
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
640
Navigating Team Friction
lara
192
16k
Practical Orchestrator
shlominoach
191
12k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
930
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
460
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
420
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.7k
Prompt Engineering for Job Search
mfonobong
0
400
[SF Ruby Conf 2025] Rails X
palkan
2
1.3k
The agentic SEO stack - context over prompts
schlessera
0
860
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