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
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
12
4.8k
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
180
AI がコードを書く時代における新卒エンジニアの仕事風景 (2026) / New Graduate Engineers in the Era of AI Coding (2026)
sushichan044
0
220
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
440
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
850
act2-costs.pdf
sumedhbala
0
110
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
230
どこまでゆるくて許されるのか
tk3fftk
0
490
Claude Team Plan導入・ガイド
tk3fftk
0
200
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
2
270
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
2
1.5k
symfony/aiとlaravel/boost
77web
0
130
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Fireside Chat
paigeccino
42
4k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
2k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
460
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
For a Future-Friendly Web
brad_frost
183
10k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
A Soul's Torment
seathinner
6
3.1k
WCS-LA-2024
lcolladotor
0
710
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
150
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