Skip to content

Commit 2955475

Browse files
committed
Merge branch 'develop'
2 parents 40e531d + 29e7ab2 commit 2955475

File tree

10 files changed

+573
-24
lines changed

10 files changed

+573
-24
lines changed

.spi.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
version: 1
2+
builder:
3+
configs:
4+
- documentation_targets: [ ManagedModels ]
5+

README.md

+3-9
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,6 @@ ManagedModels has no other dependencies.
121121
[`NSManagedObject`](https://developer.apple.com/documentation/coredata/nsmanagedobject)
122122
(superclasses can't be added by macros),
123123
e.g. `@Model class Person: NSManagedObject`.
124-
- ToMany relationships must be a `Set<Target>`, a plain `[ Target ]` cannot be
125-
used (yet?). E.g. `var contacts : Set<Contact>`.
126-
- Properties cannot be initialized in the declaration,
127-
e.g. this doesn't work: `var uuid = UUID()`.
128-
Must be done in an initializers (requirement by `@NSManaged`).
129-
- CoreData doesn't seem to support optional Swift base types like `Int?`.
130124
- Uses the CoreData `@FetchRequest` property wrapper instead `@Query`.
131125
- Doesn't use the new
132126
[Observation](https://developer.apple.com/documentation/observation)
@@ -137,13 +131,10 @@ ManagedModels has no other dependencies.
137131

138132
#### TODO
139133

140-
- [x] Archiving/Unarchiving, required for migration.
141134
- [ ] Figure out whether we can do ordered attributes: [Issue #1](https://github.com/Data-swift/ManagedModels/issues/1).
142-
- [x] Figure out whether we can add support for array toMany properties: [Issue #2](https://github.com/Data-swift/ManagedModels/issues/2)
143135
- [ ] Support for "autosave": [Issue #3](https://github.com/Data-swift/ManagedModels/issues/3)
144136
- [ ] Support transformable types, not sure they work right yet: [Issue #4](https://github.com/Data-swift/ManagedModels/issues/4)
145137
- [ ] Generate property initializers if the user didn't specify any inits: [Issue #5](https://github.com/Data-swift/ManagedModels/issues/5)
146-
- [x] Generate `fetchRequest()` class function.
147138
- [ ] Support SchemaMigrationPlan/MigrationStage: [Issue #6](https://github.com/Data-swift/ManagedModels/issues/6)
148139
- [ ] Write more tests.
149140
- [ ] Write DocC docs: [Issue #7](https://github.com/Data-swift/ManagedModels/issues/7), [Issue #8](https://github.com/Data-swift/ManagedModels/issues/8)
@@ -154,6 +145,9 @@ ManagedModels has no other dependencies.
154145
- [ ] SwiftUI `@Query` property wrapper/macro?: [Issue 12](https://github.com/Data-swift/ManagedModels/issues/12)
155146
- [ ] Figure out all the cloud sync options SwiftData has and whether CoreData
156147
can do them: [Issue 13](https://github.com/Data-swift/ManagedModels/issues/13)
148+
- [x] Archiving/Unarchiving, required for migration.
149+
- [x] Figure out whether we can add support for array toMany properties: [Issue #2](https://github.com/Data-swift/ManagedModels/issues/2)
150+
- [x] Generate `fetchRequest()` class function.
157151
- [x] Figure out whether we can allow initialized properties
158152
(`var title = "No Title"`): [Issue 14](https://github.com/Data-swift/ManagedModels/issues/14)
159153

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Differences to SwiftData
2+
3+
ManagedObjects tries to provide an API that is very close to SwiftData,
4+
but it is not exactly the same API.
5+
6+
## Differences
7+
8+
The key difference when converting SwiftData projects:
9+
- Import `ManagedModels` instead of `SwiftData`.
10+
- Let the models inherit from the CoreData
11+
[`NSManagedObject`](https://developer.apple.com/documentation/coredata/nsmanagedobject).
12+
- Use the CoreData
13+
[`@FetchRequest`](https://developer.apple.com/documentation/swiftui/fetchrequest)
14+
instead of SwiftData's
15+
[`@Query`](https://developer.apple.com/documentation/swiftdata/query).
16+
17+
18+
### Explicit Superclass
19+
20+
ManagedModels classes must explicitly inherit from the CoreData
21+
[`NSManagedObject`](https://developer.apple.com/documentation/coredata/nsmanagedobject).
22+
Instead of just this in SwiftData:
23+
```swift
24+
@Model class Contact {}
25+
```
26+
the superclass has to be specified w/ ManagedModels:
27+
```swift
28+
@Model class Contact: NSManagedObject {}
29+
```
30+
31+
> That is due to a limitation of
32+
> [Swift Macros](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/).
33+
> A macro can add protocol conformances, but it cannot add a superclass to a
34+
> type.
35+
36+
37+
### CoreData @FetchRequest instead of SwiftData @Query
38+
39+
Instead of using the new SwiftUI
40+
[`@Query`](https://developer.apple.com/documentation/swiftdata/query)
41+
wrapper, the already available
42+
[`@FetchRequest`](https://developer.apple.com/documentation/swiftui/fetchrequest)
43+
property wrapper is used.
44+
45+
SwiftData:
46+
```swift
47+
@Query var contacts : [ Contact ]
48+
```
49+
ManagedModels:
50+
```swift
51+
@FetchRequest var contacts: FetchedResults<Contact>
52+
```
53+
54+
### Properties
55+
56+
The properties work quite similar.
57+
58+
Like SwiftData, ManagedModels provides implementations of the
59+
[`@Attribute`](https://developer.apple.com/documentation/swiftdata/attribute(_:originalname:hashmodifier:)),
60+
`@Relationship` and
61+
[`@Transient`](https://developer.apple.com/documentation/swiftdata/transient())
62+
macros.
63+
64+
#### Compound Properties
65+
66+
More complex Swift types are always stored as JSON by ManagedModels, e.g.
67+
```swift
68+
@Model class Person: NSManagedObject {
69+
70+
struct Address: Codable {
71+
var street : String?
72+
var city : String?
73+
}
74+
75+
var privateAddress : Address
76+
var businessAddress : Address
77+
}
78+
```
79+
80+
SwiftData decomposes those structures in the database.
81+
82+
83+
#### RawRepresentable Properties
84+
85+
Those end up working the same like in SwiftData, but are implemented
86+
differently.
87+
If a type is RawRepresentable by a CoreData base type (like `Int` or `String`),
88+
they get mapped to the same base type in the model.
89+
90+
Example:
91+
```swift
92+
enum Color: String {
93+
case red, green, blue
94+
}
95+
96+
enum Priority: Int {
97+
case high = 5, medium = 3, low = 1
98+
}
99+
```
100+
101+
102+
### Initializers
103+
104+
A CoreData object has to be initialized through some
105+
[very specific initializer](https://developer.apple.com/documentation/coredata/nsmanagedobject/1506357-init),
106+
while a SwiftData model class _must have_ an explicit `init`,
107+
but is otherwise pretty regular.
108+
109+
The ManagedModels `@Model` macro generates a set of helper inits to deal with
110+
that.
111+
But the general recommendation is to use a `convenience init` like so:
112+
```swift
113+
convenience init(title: String, age: Int = 50) {
114+
self.init()
115+
title = title
116+
age = age
117+
}
118+
```
119+
If the own init prefilles _all_ properties (i.e. can be called w/o arguments),
120+
the default `init` helper is not generated anymore, another one has to be used:
121+
```swift
122+
convenience init(title: String = "", age: Int = 50) {
123+
self.init(context: nil)
124+
title = title
125+
age = age
126+
}
127+
```
128+
The same `init(context:)` can be used to insert into a specific context.
129+
Often necessary when setting up relationships (to make sure that they
130+
live in the same
131+
[`NSManagedObjectContext`](https://developer.apple.com/documentation/coredata/nsmanagedobjectcontext)).
132+
133+
134+
### Migration
135+
136+
Regular CoreData migration mechanisms have to be used.
137+
SwiftData specific migration APIs might be
138+
[added later](https://github.com/Data-swift/ManagedModels/issues/6).
139+
140+
141+
## Implementation Differences
142+
143+
SwiftData completely wraps CoreData and doesn't expose the CoreData APIs.
144+
145+
SwiftData relies on the
146+
[Observation](https://developer.apple.com/documentation/observation)
147+
framework (which requires iOS 17+).
148+
ManagedModels uses CoreData, which makes models conform to
149+
[ObservableObject](https://developer.apple.com/documentation/combine/observableobject)
150+
to integrate w/ SwiftUI.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# ``ManagedModels``
2+
3+
SwiftData like declarative schemas for CoreData.
4+
5+
@Metadata {
6+
@DisplayName("ManagedModels for CoreData")
7+
}
8+
9+
## Overview
10+
11+
[ManagedModels](https://github.com/Data-swift/ManagedModels/) is a package
12+
that provides a
13+
[Swift 5.9](https://www.swift.org/blog/swift-5.9-released/)
14+
macro similar to the SwiftData
15+
[@Model](https://developer.apple.com/documentation/SwiftData/Model()).
16+
It can generate CoreData
17+
[ManagedObjectModel](https://developer.apple.com/library/archive/documentation/DataManagement/Devpedia-CoreData/managedObjectModel.html)'s
18+
declaratively from Swift classes,
19+
w/o having to use the Xcode "CoreData Modeler".
20+
21+
Unlike SwiftData it doesn't require iOS 17+ and works directly w/
22+
[CoreData](https://developer.apple.com/documentation/coredata).
23+
It is **not** a direct API replacement, but a look-a-like.
24+
Example model class:
25+
```swift
26+
@Model
27+
class ToDo: NSManagedObject {
28+
var title: String
29+
var isDone: Bool
30+
var attachments: [ Attachment ]
31+
}
32+
```
33+
Setting up a store in SwiftUI:
34+
```swift
35+
ContentView()
36+
.modelContainer(for: ToDo.self)
37+
```
38+
Performing a query:
39+
```swift
40+
struct ToDoListView: View {
41+
@FetchRequest(sort: \.isDone)
42+
private var toDos: FetchedResults<ToDo>
43+
44+
var body: some View {
45+
ForEach(toDos) { todo in
46+
Text("\(todo.title)")
47+
.foregroundColor(todo.isDone ? .green : .red)
48+
}
49+
}
50+
}
51+
```
52+
53+
- Swift package: [https://github.com/Data-swift/ManagedModels.git](https://github.com/Data-swift/ManagedModels/)
54+
- Example ToDo list app: [https://github.com/Data-swift/ManagedToDosApp.git](https://github.com/Data-swift/ManagedToDosApp/)
55+
56+
57+
58+
## Topics
59+
60+
### Getting Started
61+
62+
- <doc:GettingStarted>
63+
- <doc:DifferencesToSwiftData>
64+
65+
### Support
66+
67+
- <doc:FAQ>
68+
- <doc:Links>
69+
- <doc:Who>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Frequently Asked Questions
2+
3+
A collection of questions and possible answers.
4+
5+
## Overview
6+
7+
Any question we should add: [[email protected]](mailto:[email protected]),
8+
file a GitHub [Issue](https://github.com/Data-swift/ManagedModels/issues).
9+
or submit a GitHub PR w/ the answer. Thank you!
10+
11+
## General
12+
13+
### Is the API the same like in SwiftData?
14+
15+
The API is very similar, but there are some significant differences:
16+
<doc:DifferencesToSwiftData>.
17+
18+
### Is ManagedObjects a replacement for SwiftData?
19+
20+
It is not exactly the same but can be used as one, yes.
21+
ManagedObjects allows deployment on earlier versions than iOS 17 or macOS 14
22+
while still providing many of the SwiftData benefits.
23+
24+
It might be a sensible migration path towards using SwiftData directly in the
25+
future.
26+
27+
### Which deployment versions does ManagedObjects support?
28+
29+
While it might be possible to backport further, ManagedObjects currently
30+
supports:
31+
- iOS 13+
32+
- macOS 11+
33+
- tvOS 13+
34+
- watchOS 6+
35+
36+
### Does this require SwiftUI or can I use it in UIKit as well?
37+
38+
ManagedObjects works with both, SwiftUI and UIKit.
39+
40+
In a UIKit environment the ``ModelContainer`` (aka ``NSPersistentContainer``)
41+
needs to be setup manually, e.g. in the `ApplicationDelegate`.
42+
43+
Example:
44+
```swift
45+
import ManagedModels
46+
47+
let schema = Schema([ Item.self ])
48+
let container = try ModelContainer(for: schema, configurations: [])
49+
```
50+
51+
### Are the `ModelContainer`, `Schema` classes subclasses of CoreData classes?
52+
53+
No, most of the SwiftData-like types provided by ManagedObjects are just
54+
"typealiases" to the corresponding CoreData types, e.g.:
55+
- ``ModelContainer`` == ``NSPersistentContainer``
56+
- ``ModelContext`` == ``NSManagedObjectContext``
57+
- ``Schema`` == ``NSManagedObjectModel``
58+
- `Schema/Entity` == ``NSEntityDescription``
59+
60+
And so on. The CoreData type names can be used instead, but make a future
61+
migration to SwiftData harder.
62+
63+
### Is it possible to use ManagedModels in SwiftUI Previews?
64+
65+
Yes! Attach an in-memory store to the preview-View, like so:
66+
```swift
67+
#Preview {
68+
ContentView()
69+
.modelContainer(for: Item.self, inMemory: true)
70+
}
71+
```
72+
73+
### Something isn't working right, how do I file a Radar?
74+
75+
Please file a GitHub
76+
[Issue](https://github.com/Data-swift/ManagedModels/issues).
77+
Thank you very much.

0 commit comments

Comments
 (0)