multi-threaded coredata done right
DESCRIPTION
Slides from my 360|iDev talk on how to concurrently fetch, parse, and save data while allowing user interaction to continue smoothly.TRANSCRIPT
Multi-threaded Core Data Done Right
Andrew Morrow
Multi-threaded Core Data Done Right
Andrew Morrow
Let’s Build a CoreData Stack!
Goals
1. Never block UI interaction
2. Efficiently handle large datasets
3. Display updated data immediately
4. Avoid data merge conflicts
First Try (Demo)
What Went Wrong?
Main Queue Background Queue
getAsynchronous
Main Queue Background Queue
getAsynchronous
Main Queue Background Queue
Network Request
getAsynchronous
dispatch_async
Main Queue Background Queue
Main Queue MOC
Network Request
getAsynchronous
dispatch_async
! Parse and Save
Main Queue Background Queue
Main Queue MOC
Network Request
getAsynchronous
dispatch_async
! Parse and Save
User Interaction
Main Queue Background Queue
Main Queue MOC
Network Request
Move Parsing and Saving onto a Background Queue
(Demo)
What Went Wrong?
Main Queue Background Queue
getAsynchronous
Main Queue Background Queue
getAsynchronous
Main Queue Background Queue
Network Request
getAsynchronous
performBlock
Main Queue Background Queue
Background MOC
Network Request
getAsynchronous
performBlock
Parse and Save? User Interaction
Main Queue Background Queue
Background MOC
Network Request
getAsynchronous
performBlock
Parse and Save? User Interaction
Main Queue Background Queue
Background MOC
Network Request?!
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Solution: Multiple Persistent Store Coordinators
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Persistent Store Coordinator
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Persistent Store Coordinator
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Persistent Store Coordinator
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Persistent Store Coordinator
Read-Only
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Persistent Store Coordinator
Read-Only
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Persistent Store Coordinator
Read-Only
Main Queue MOC
Background MOC
Persistent Store Coordinator
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Persistent Store Coordinator
Read-Only Read-Write
Write-Ahead Logging (WAL)
1 2 3 4 5
Reader(s)
Write-Ahead Logging (WAL)
1 2 3 4 5
Reader(s)
6
Writer
Write-Ahead Logging (WAL)
1 2 3 4 5
Reader(s)
6
Write-Ahead Logging (WAL)
1 2 3 4 5
Reader(s)
6
Write-Ahead Logging (WAL) (cont.)
SQLite feature
Multiple concurrent reads
One concurrent write
Shared memory between readers and writers for synchronization
Good News!
Good News!@{NSSQLitePragmasOption: @{@"journal_mode": @"WAL"}}
Parallel Persistent Store Coordinators
(Demo)
What Went Wrong?
Updating the Main Thread
Main Queue MOC
Background MOC
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Updating the Main Thread
Main Queue MOC
Background MOC
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Background MOC
Updating the Main Thread
Main Queue MOC
Background MOC
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Background MOC
SQLite
Updating the Main Thread
Main Queue MOC
Background MOC
User Interaction (Fetched Results Controller)
SQLite
Remote Data Refresh (Parse and Save)
Background MOC
SQLite
Updating the Main Thread (Cont.)Merging changes from notifications
Batched saves
Custom notifications
Completion blocks
NSManagedObjectID
Updating the Main Thread (Demo)
Avoiding Merge Conflicts
Serialize CoreData write access
Keep main thread read-only
SQLite (Jennifer)
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC (Jennifer)
SQLite (Jennifer)
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC (Jennifer)
Background MOC (Jen)
SQLite (Jennifer)
SQLite (Jen)
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC (Jennifer)
Background MOC (Jen)
SQLite (Jennifer)
SQLite (Jen)
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC (Jennifer)
Background MOC (Jen)
Main Queue MOC (Jen)
SQLite (Jennifer)
SQLite (Jen)
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC (Jennifer)
Background MOC (Jen)
Main Queue MOC (Jen)
→ Jen
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC Queue
→ Jen
SQLite (Jennifer)
→ Jen
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC Queue
→ Jen
SQLite (Jennifer)
→ Jen
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC Queue
→ Jen
SQLite (Jennifer)
SQLite (Jen)
→ Jen
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC Queue
→ Jen
SQLite (Jennifer)
SQLite (Jen)
Main Queue MOC (Jen)
→ Jen
Main Queue MOC (Jennifer)
User Interaction Jennifer → Jen
Remote Data Refresh Jennifer → Jen
Background MOC Queue
→ JenSQLite (Jennifer)
SQLite (Jen)
Main Queue MOC (Jen)
Summary
Let SQLite handle your concurrency
Only allow one concurrent write
Keep your main thread read-only
“CoreData Performance” Tim Isted, WWDC 2013 #211
Questions
Questions