Skip to content

Commit 526fd32

Browse files
committed
Update README.md
1 parent 23e83f2 commit 526fd32

1 file changed

Lines changed: 27 additions & 15 deletions

File tree

README.md

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Helpful tools for Core Data
3030

3131
## What Is It?
3232

33-
Core Data is a big and powerful tool, but it has never felt to me that it’s easy to learn. I’ve been using it heavily for years, and I still get confused when I try to do new things with it. **RCDataKit** is a collection of helper tools I’ve made over the years to make Core Data development and learning just a little easier.
33+
Core Data is a big and powerful tool, but it has never felt to me that it’s easy to learn. I’ve been using it heavily for years, and I still get confused when I try to do new things with it. **RCDataKit** is a collection of helper tools I’ve made over the years to make it all just a little easier.
3434

3535
**RCDataKit** is a work in progress, and I’m intentionally keeping it fairly simple so that beginners can hopefully learn from it by browsing the source code. If you want something a lot more powerful, check out these really great libraries:
3636

@@ -69,8 +69,6 @@ Or add the package to your Xcode project with `File -> Add Package Dependencies.
6969

7070
# Creating a Data Stack
7171

72-
**RCDataKit** has a few pre-made solutions for setting up your Core Data stack. They’re not required for use with any of the other types in the library, but they do most of the setup work for you.
73-
7472
## DataStack Protocol
7573
This simple protocol is for types that wrap a `NSPersistentContainer` and provide pre-configured `NSManagedObjectContexts`.
7674

@@ -83,6 +81,9 @@ let viewContext = myStack.viewContext
8381

8482
// Get a background context where transactionAuthor == TransactionAuthor.cloudDataImport.name
8583
let bgContext = myStack.backgroundContext(author: .cloudDataImport)
84+
85+
// TransactionAuthor can also be initialized with a String literal
86+
let anotherContext = myStack.backgroundContext(author: "otherContext")
8687
```
8788

8889
### Default DataStack Implementations
@@ -109,6 +110,13 @@ extension TransactionAuthor {
109110
}
110111
```
111112

113+
Or you can create names for your `TransactionAuthor`s at the call site by just using String literals:
114+
115+
```swift
116+
let someContext = myStack.backgroundContext(author: "EditingTransaction")
117+
```
118+
119+
112120
### ModelManager and ModelFileManager Protocols
113121

114122
These two paired protocols (mostly `ModelFileManager`, which inherits from `ModelManager`) are required by several other parts of this library to automate some of the boilerplate in creating a `NSManagedObjectModel`. The `ModelFileManager` represents the `.xcdatamodeld` file that most of us use to create our managed object model.
@@ -138,16 +146,18 @@ Then you can use your `ModelFileManager` type in initializers for `BasicDataStac
138146

139147
Migrating your Model from one version to the next can be a huge pain— Lightweight Migrations are easy enough, but Custom Migrations not so much. But now we have [Staged Migrations](https://developer.apple.com/videos/play/wwdc2022/10120/)! Unfortunately, [Apple’s documentation](https://developer.apple.com/documentation/coredata/staged_migrations) is lacking. Thanks to [Pol Piela](https://www.polpiella.dev/staged-migrations) and [FatBobMan](https://fatbobman.com/en/posts/what-s-new-in-core-data-in-wwdc23/) for picking up the slack.
140148

141-
With the `ModelVersion` protocol, setting up staged migrations takes a lot less boilerplate code, so you can do the important work.
149+
With the `ModelVersion` protocol, setting up staged migrations takes a lot less boilerplate code, so you can focus on the important work of performing the migration.
142150

143-
1. Make a type that conforms to the protocol, and make it reference the names of your model versions, and give it a `ModelFileManager` type:
151+
1. Make a type that conforms to the protocol, have it reference the names of your model versions, and give it a `ModelFileManager` type:
144152

145153
<img width="160" alt="Screenshot_2024-09-15_at_10 24 58_AM" src="https://github.com/user-attachments/assets/9a42ca82-72c2-4c17-afa7-7bba80fa9f7a">
146154

147155
```swift
148156
enum Versions: String, ModelVersion {
157+
// See `ModelFileManager` protocol:
149158
typealias ModelFile = TestModelFile
150159

160+
// One case per version in your xcdatamodeld file:
151161
case v1 = "Model"
152162
case v2 = "Model2"
153163
case v3 = "Model3"
@@ -245,14 +255,14 @@ struct MyView: View {
245255
}
246256
```
247257

248-
The `.dataStackEnvironment(_:)` call wraps `.environment(_:,_:)` calls for both the DataStack and ManagedObjectContext, so you can access either environment value with the following property wrappers:
258+
The `.dataStackEnvironment(_:)` call wraps `.environment(_:_:)` calls for both the DataStack and ManagedObjectContext, so you can access either environment value with the following property wrappers:
249259

250260
```swift
251261
struct SubView: View {
252-
/// This is a NSManagedObjectContext accessed by `myStack.viewContext`
262+
/// This is a `NSManagedObjectContext` accessed by `myStack.viewContext`
253263
@Environment(\.managedObjectContext) var context
254264

255-
/// This is a (any DataStack)? equal to `myStack` from MyView.
265+
/// This is a `any DataStack` equal to `myStack` from `MyView`.
256266
@EnvironmentDataStack var dataStack
257267

258268
var body: some View { ... }
@@ -268,7 +278,7 @@ You must set the DataStack into a view's environment using the `dataStackEnviron
268278
Use `TypedObjectID` in place of `NSManagedObjectID` anywhere that you want to enforce type safety around the ID. Because both `NSManagedObjectID` and the `TypedObjectID` wrapper are `Sendable`, they are the best way to send references to `NSManagedObject` between contexts.
269279
```swift
270280
let viewContextPerson = Person(...) // get a person on the ViewContext
271-
let personId = TypedObjectID(viewContextPerson.objectID) // personId refers only to Person type
281+
let personId = TypedObjectID(viewContextPerson) // personId refers only to Person type
272282

273283
try backgroundContext.perform {
274284
// get a reference to the same Person from storage, but safe for this context:
@@ -348,20 +358,20 @@ let dictionaryResults: [ImportablePerson.ID : PersistenceResult] = try context
348358

349359
There are some extra functions in an extension of `NSManagedObjectContext` help with basic operations:
350360

351-
Save changes, but only if changes exist in the context. If you update object properties with the `Updatable` protocol functions, this will save you unnecessary `save()` calls.
361+
- Save changes, but only if changes exist in the context. If you update object properties with the `Updatable` protocol functions, this will save you unnecessary `save()` calls.
352362

353363
```swift
354364
try context.saveIfNeeded()
355365
```
356366

357-
Get typed `NSManagedObjects` from the context.
367+
- Get typed `NSManagedObjects` from the context.
358368

359369
```swift
360370
let somePerson = try context.existing(Person.self, withID: personID)
361371
let somePeople = try context.existing(Person.self, withIDs: [ID1, ID2, ID3])
362372
```
363373

364-
Remove all objects of a given type from the context (with an optional `NSPredicate` to only remove objects that match the given criteria).
374+
- Remove all objects of a given type from the context (with an optional `NSPredicate` to only remove objects that match the given criteria).
365375

366376
```swift
367377
try context.removeInstances(of: Person.self, matching: someNSPredicate)
@@ -388,7 +398,7 @@ let sorting: [NSSortDescriptor] = [
388398

389399
### NSPredicate Helpers
390400

391-
`NSPredicate`s can be combined with `&&`, `||`, and `!` operators
401+
`NSPredicate` can be combined with `&&`, `||`, and `!` operators
392402

393403
```swift
394404
let predicate1 = NSPredicate(format: "'age' >= 13")
@@ -399,7 +409,7 @@ let isNotTeenager = !isTeenager
399409
let alsoIsNotTeenager = !predicate1 || !predicate2
400410
```
401411

402-
You can also use `KeyPath`s on `NSManagedObject` subclasses to make simple predicates:
412+
You can also use `KeyPath` on `NSManagedObject` subclasses to make simple predicates:
403413

404414
```swift
405415
// Simple Equatable or Comparable KeyPaths allow this kind of NSPredicate creation
@@ -431,4 +441,6 @@ For a more robust, elegant, and type-safe `NSPredicate` system, check out [Predi
431441

432442
## Contribution/Feedback
433443

434-
And since it’s a work-in-progress, I’m happy to receive suggestions, feedback, or contributions to it. Create an issue or pull request if you like.
444+
Since it’s a work-in-progress, I’m happy to receive suggestions, feedback, or contributions. Create an issue or pull request if you like.
445+
446+
And please browse the code and use it however you please. I hope that it can help you learn a few things about Core Data that you can use in your own projects. Cheers!

0 commit comments

Comments
 (0)