SwiftData Suprises
I've started working on a new app as a side project and because WWDC was just a few weeks ago decided to play with some of the new APIs introduced – namely SwiftData. Consider this class:
@Model
final class Company {
var name: String
@Relationship(inverse: \Person.company)
var employees: [Employee] // `Employee` is also a class annotated with @Model
}
My surprises came when I started adding some tests around my new models. For somewhat contrived reasons, let's say that when a company gets created there is 1 employee.
func test_newCompany_hasEmployeeAttached() throws {
let company = Company(name: "Great Co.")
XCTAssertEqual(1, company.employees.count)
}
This test fails in 2 ways:
- I get a crash at the init on the first line because there is no configured container.
- I get a crash when accessing the array (which should have 1 auto-inserted value).
I fix the test by adding the container, and then inserting the company
in to the container's context:
func test_newCompany_hasEmployeeAttached() throws {
let context = // create the container
let company = Company(name: "Great Co.")
context.insert(company)
XCTAssertEqual(1, company.employees.count)
}
What stands out to me is that it sure feels like SwiftData classes are your own classes. But they're not. They gain a conformance to PersistentModel
and have all of their persisted properties rewritten with generated getters and setters. So yeah the class does not inherit from NSManagedObject
but it's also not a class that is unencumbered from implicit behavior to be aware of.
I think this is teaching me that there are nuances to using SwiftData and macros in general.
I've started working on a new app as a side project and because WWDC was just a few weeks ago decided to play with some of the new APIs introduced – namely SwiftData. Consider this class:
@Model
final class Company {
var name: String
@Relationship(inverse: \Person.company)
var employees: [Employee] // `Employee` is also a class annotated with @Model
}
My surprises came when I started adding some tests around my new models. For somewhat contrived reasons, let's say that when a company gets created there is 1 employee.
func test_newCompany_hasEmployeeAttached() throws {
let company = Company(name: "Great Co.")
XCTAssertEqual(1, company.employees.count)
}
This test fails in 2 ways:
- I get a crash at the init on the first line because there is no configured container.
- I get a crash when accessing the array (which should have 1 auto-inserted value).
I fix the test by adding the container, and then inserting the company
in to the container's context:
func test_newCompany_hasEmployeeAttached() throws {
let context = // create the container
let company = Company(name: "Great Co.")
context.insert(company)
XCTAssertEqual(1, company.employees.count)
}
What stands out to me is that it sure feels like SwiftData classes are your own classes. But they're not. They gain a conformance to PersistentModel
and have all of their persisted properties rewritten with generated getters and setters. So yeah the class does not inherit from NSManagedObject
but it's also not a class that is unencumbered from implicit behavior to be aware of.
I think this is teaching me that there are nuances to using SwiftData and macros in general.