You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+27-15Lines changed: 27 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,7 +30,7 @@ Helpful tools for Core Data
30
30
31
31
## What Is It?
32
32
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.
34
34
35
35
**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:
36
36
@@ -69,8 +69,6 @@ Or add the package to your Xcode project with `File -> Add Package Dependencies.
69
69
70
70
# Creating a Data Stack
71
71
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
-
74
72
## DataStack Protocol
75
73
This simple protocol is for types that wrap a `NSPersistentContainer` and provide pre-configured `NSManagedObjectContexts`.
76
74
@@ -83,6 +81,9 @@ let viewContext = myStack.viewContext
83
81
84
82
// Get a background context where transactionAuthor == TransactionAuthor.cloudDataImport.name
85
83
let bgContext = myStack.backgroundContext(author: .cloudDataImport)
84
+
85
+
// TransactionAuthor can also be initialized with a String literal
86
+
let anotherContext = myStack.backgroundContext(author: "otherContext")
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
+
112
120
### ModelManager and ModelFileManager Protocols
113
121
114
122
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
138
146
139
147
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.
140
148
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.
142
150
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:
// One case per version in your xcdatamodeld file:
151
161
casev1="Model"
152
162
casev2="Model2"
153
163
casev3="Model3"
@@ -245,14 +255,14 @@ struct MyView: View {
245
255
}
246
256
```
247
257
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:
249
259
250
260
```swift
251
261
structSubView: View {
252
-
/// This is a NSManagedObjectContext accessed by `myStack.viewContext`
262
+
/// This is a `NSManagedObjectContext` accessed by `myStack.viewContext`
253
263
@Environment(\.managedObjectContext) var context
254
264
255
-
/// This is a (any DataStack)? equal to `myStack` from MyView.
265
+
/// This is a `any DataStack` equal to `myStack` from `MyView`.
256
266
@EnvironmentDataStackvar dataStack
257
267
258
268
var body: some View { ... }
@@ -268,7 +278,7 @@ You must set the DataStack into a view's environment using the `dataStackEnviron
268
278
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.
269
279
```swift
270
280
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
272
282
273
283
try backgroundContext.perform {
274
284
// get a reference to the same Person from storage, but safe for this context:
There are some extra functions in an extension of `NSManagedObjectContext` help with basic operations:
350
360
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.
352
362
353
363
```swift
354
364
try context.saveIfNeeded()
355
365
```
356
366
357
-
Get typed `NSManagedObjects` from the context.
367
+
-Get typed `NSManagedObjects` from the context.
358
368
359
369
```swift
360
370
let somePerson =try context.existing(Person.self, withID: personID)
361
371
let somePeople =try context.existing(Person.self, withIDs: [ID1, ID2, ID3])
362
372
```
363
373
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).
@@ -388,7 +398,7 @@ let sorting: [NSSortDescriptor] = [
388
398
389
399
### NSPredicate Helpers
390
400
391
-
`NSPredicate`s can be combined with `&&`, `||`, and `!` operators
401
+
`NSPredicate` can be combined with `&&`, `||`, and `!` operators
392
402
393
403
```swift
394
404
let predicate1 =NSPredicate(format: "'age' >= 13")
@@ -399,7 +409,7 @@ let isNotTeenager = !isTeenager
399
409
let alsoIsNotTeenager =!predicate1 ||!predicate2
400
410
```
401
411
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:
403
413
404
414
```swift
405
415
// 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
431
441
432
442
## Contribution/Feedback
433
443
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