Hi, does anyone know how to get @Relationship in SwiftData to cascade to the CloudKit container? I've managed to get SwiftData classes to show up in CloudKit but they are not related in line with the @Relationship as per the example project:
@Relationship(.cascade)
var bucketListItem: [BucketListItem] = []`
They are simply separate records. As result the cascade of deletes doesn't work.
Any ideas?
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Post
Replies
Boosts
Views
Activity
Hi, I want to subclass my model.
Here is my superclass:
import SwiftData
@Model
public class Control {
@Attribute(.unique)
public var frame: Frame
init(frame: Frame) {
self.frame = frame
}
}
Here is my subclass:
import SwiftData
import CoreGraphics
class SliderControl: Control {
let axis: Axis
var value: CGFloat = 0.0
init(axis: Axis, frame: Frame) {
self.axis = axis
super.init(frame: frame)
}
required public init(backingData: any BackingData<Control>, fromFetch: Bool = false) {
// How to get `axis` and `value` from the backing data?
}
}
I'm not sure how to use the backing data to re-create my object.
My goal is to have multiple controls with unique properties.
Using SwiftData, I have a model that uses an enum as a property and a custom Codable type
import SwiftData
import CoreLocation
// MARK: - Main Model
@Model
class Cache {
var size: CacheSize?
var coordinates: CLLocationCoordinate2D
}
// MARK: - CacheSize Enum
enum CacheSize: CaseIterable, Codable {
case nano
case micro
case small
case regular
case large
case veryLarge
case notChosen
case virtual
case other
}
// MARK: - Codable for CLLocationCoordinate2D
extension CLLocationCoordinate2D: Codable {
enum CodingKeys: String, CodingKey {
case lat, lng
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.latitude, forKey: .lat)
try container.encode(self.longitude, forKey: .lng)
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let latitude = try container.decode(CLLocationDegrees.self, forKey: .lat)
let longitude = try container.decode(CLLocationDegrees.self, forKey: .lng)
self.init(latitude: latitude, longitude: longitude)
}
}
When I fetch the object from the ModelContext and try to access the property corresponding to this enum, I have a fatal error raised in BackingData.swift:
SwiftData/BackingData.swift:197: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(iGeo.CacheSize, Swift.DecodingError.Context(codingPath: [], debugDescription: "Invalid number of keys found, expected one.", underlyingError: nil))
When I try to read the CLLocationCoordinates2D property, I have also a crash in the Decodable init(from decoder: Decoder implementation when trying to read the first value from the container.
Did I miss something here or did something wrong?
I test with a simple class and it can compile:
@Model
final class Book: Encodable {
var name: String
enum CodingKeys: CodingKey {
case name
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
}
}
Then I try with the Trip class from sample and it cause an error:
@Model final class Trip: Encodable {
:
enum CodingKeys: CodingKey {
case name, destination, endDate, startDate, bucketList
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(destination, forKey: .destination)
try container.encode(endDate, forKey: .endDate)
try container.encode(startDate, forKey: .startDate)
try container.encode(bucketList as! Set<BucketListItem>, forKey: .bucketList)
}
And I got the error Ambiguous use of 'setValue(for:to:)'
I tried make BucketListItem and LivingAccommodation Encodable and still have error.
I haven’t found any way to have a swift data model contain an enum with different associated values, each different types of
models, in order to deal with models that require heterogenous collections. Is this simply not supported? Is it supported but not ever used with SwiftUI binding? Instead I’ve had to create my own sort of enum in the form of a model that contains optionals for every case but this is obviously not ideal.
I'm trying out SwiftData and converting my existing data models using Structs and Codable to Classes and SwiftData. I've got a model that has a Measurement<UnitMass> type. When I run the app after converting everything to use classes with the @Model macro, I get a fatal error: SwiftData/SchemaProperty.swift:325: Fatal error: Unexpected type for CompositeAttribute: NSUnitMass.
Since Measurement conforms to Codable, and SwiftData should work with Codable types, why is this not working?
I also tried marking the property with @Attribute(.transformable) and it didn't make a difference.
Running my app with SwiftData in iOS 17 beta on iPhone leads to error:
cannot open file at line 46973 of [554764a6e7]
os_unix.c:46973: (2) open(/private/var/mobile/Containers/Data/Application/ED4308D5-058B-41BC-A617-A46F9754E3EC/Library/Application Support/default.store) - No such file or directory
API call with unopened database connection pointer
misuse at line 179760 of [554764a6e7]
It seems the database file has not been created yet, since it's the first time running the app with SwiftData.
In Xcode Version 15.0 beta (15A5160n) this predicate will not build:
let thisPredicate = #Predicate<Ledgers> {
($0.myStore != nil)
}
The definition of .myStore in the Ledgers class is:
var myStore: Stores?
an optional relationship. Is there anyway to test for nil optional relationships in SwiftData?
The inverse relationship in Stores is:
@Relationship(.deny, inverse: \Ledgers.myStore) var myReceipts: [Ledgers]
Hi,
I am looking for information on how to setup a ModelContainer for a Swift app when the SwiftData model is located in a Swift package.
Let's say the model code resides in a package called DomainModel. That package was added target's embedded content and the model types are used to init the model container using the modelContainer(for:) view modifier on the ContentView of the app.
This crashes the app on startup with a EXC_BAD_ACCESS code=2. When copying the model code from the package directly into the app, the app starts just fine.
I kindly ask for a code sample or any information about how to setup the model container when using a model from a Swift package.
Thanks in advance and I am looking forward to replacing CoreData 🙂
Hi,
if I have a @Model class there's always an id: PersistentIdentifier.ID underneath which, according to the current documentation "The value that uniquely identifies the associated model within the containing store.".
So I am wondering if it is (good) enough to rely on this attribute to uniquely identify @Model class entities, or if there are edge cases where it does not work (like maybe when using CloudKit)?
If anybody saw some information regarding this, please let me know :-)
Cheers,
Michael
I have an app that uses CoreData and I want to migrate to SwiftData. After following the Migrate to SwiftData session, I only need to point to my old Core Data file to read the old data and convert it to the new SwiftData format.
My question is how do I do this? Maybe worth mentioning is that my NSPersistentContainer(name: "Model") is different to my app name.
Possible Solution?
According to a Tweet by Donny Wals this is done this way:
By default a SwiftData ModelContainer will create its underlying storage in a file called default.store. If you want to change this so you can use an existing Core Data SQLite file, you can point your container to that file instead:
// point to your old sqlite file
let url = URL.applicationSupportDirectory.appending(path: "Model.sqlite")
let config = ModelConfiguration(url: url)
modelContainer = try ModelContainer(for: [
Movie.self
], config)
My Tested Code
@main
struct SwiftData_TestApp: App {
let url = URL.applicationSupportDirectory.appending(path: "Model.sqlite")
let config = ModelConfiguration(url: url)
let modelContainer = try ModelContainer(for: [
Item.self
], config)
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(modelContainer)
}
}
The problem here is that I don’t get it to work in the main app struct. When using this the way described in Dive deeper into SwiftData (at 6:58) I only get the error: Cannot use instance member 'url' within property initializer; property initializers run before 'self' is available
PS: There seems to be an issue with this WWDC session method anyway – see this post.
It seems that @Model is not fully supported in visionOS. I've tried both an iPad app and a native visionOS app, and both crash when trying to use SwiftData. It's a minimal app from the template (no data) that I add a little data code to:
import SwiftData
@Model
final class mapPin {
var lat : Double
var lon : Double
init(lat: Double, lon: Double) {
self.lat = lat
self.lon = lon
}
}
Building for visionOS produces:
/var/folders/9p/ppkjrfhs393__cqm9z57k9mr0000gn/T/swift-generated-sources/@__swiftmacro_7Vision16mapPin5ModelfMm_.swift:2:13: error: declaration name '_$backingData' is not covered by macro 'Model'
private var _$backingData: any SwiftData.BackingData<mapPin> = SwiftData.DefaultBackingData(for: mapPin.self)
^
/Users/arenberg/Developer/Beta/Vision1/Vision1/ContentView.swift:13:7: note: in expansion of macro 'Model' here
final class mapPin {
^~~~~~~~~~~~~~
/var/folders/9p/ppkjrfhs393__cqm9z57k9mr0000gn/T/swift-generated-sources/@__swiftmacro_7Vision16mapPin5ModelfMc_.swift:1:1: error: type 'mapPin' does not conform to protocol 'PersistentModel'
extension mapPin : SwiftData.PersistentModel {}
^
/Users/arenberg/Developer/Beta/Vision1/Vision1/ContentView.swift:13:7: note: in expansion of macro 'Model' here
final class mapPin {
^~~~~~~~~~~~~~
/var/folders/9p/ppkjrfhs393__cqm9z57k9mr0000gn/T/swift-generated-sources/@__swiftmacro_7Vision16mapPin5ModelfMc_.swift:1:1: note: do you want to add protocol stubs?
extension mapPin : SwiftData.PersistentModel {}
^
/Users/arenberg/Developer/Beta/Vision1/Vision1/ContentView.swift:13:7: note: in expansion of macro 'Model' here
final class mapPin {
^~~~~~~~~~~~~~
/var/folders/9p/ppkjrfhs393__cqm9z57k9mr0000gn/T/swift-generated-sources/@__swiftmacro_7Vision16mapPin5ModelfMm_.swift:2:64: error: module 'SwiftData' has no member named 'DefaultBackingData'
private var _$backingData: any SwiftData.BackingData<mapPin> = SwiftData.DefaultBackingData(for: mapPin.self)
^~~~~~~~~ ~~~~~~~~~~~~~~~~~~
/Users/arenberg/Developer/Beta/Vision1/Vision1/ContentView.swift:13:7: note: in expansion of macro 'Model' here
final class mapPin {
^~~~~~~~~~~~~~```
Hi,
when inserting an entity with a relationship I get the following runtime error:
Illegal attempt to establish a relationship 'group' between objects in different contexts [...].
The model looks like this:
@Model
class Person {
var name: String
@Relationship(.nullify, inverse: \Group.members) var group: Group
init(name: String) {
self.name = name
}
}
@Model
class Group {
var name: String
@Relationship(.cascade) public var members: [Person]
init(name: String) {
self.name = name
}
}
It can be reproduced using this (contrived) bit of code:
let group = Group(name: "Group A")
ctx.insert(group)
try! ctx.save()
let descriptor = FetchDescriptor<Group>()
let groups = try ctx.fetch(descriptor)
XCTAssertFalse(groups.isEmpty)
XCTAssertEqual(groups.count, 1)
XCTAssertTrue(groups.first?.name == "Group A")
let person = Person(name: "Willy")
person.group = group
ctx.insert(person)
try ctx.save()
(See also full test case below).
Anybody experiencing similar issues? Bug or feature?
Cheers, Michael
Full test case:
import SwiftData
import SwiftUI
import XCTest
// MARK: - Person -
@Model
class Person {
var name: String
@Relationship(.nullify, inverse: \Group.members) var group: Group
init(name: String) {
self.name = name
}
}
// MARK: - Group -
@Model
class Group {
var name: String
@Relationship(.cascade) public var members: [Person]
init(name: String) {
self.name = name
}
}
// MARK: - SD_PrototypingTests -
final class SD_PrototypingTests: XCTestCase {
var container: ModelContainer!
var ctx: ModelContext!
override func setUpWithError() throws {
let fullSchema = Schema([Person.self,
Group.self,])
let dbCfg = ModelConfiguration(schema: fullSchema)
container = try ModelContainer(for: fullSchema, dbCfg)
ctx = ModelContext(container)
_ = try ctx.delete(model: Group.self)
_ = try ctx.delete(model: Person.self)
}
override func tearDownWithError() throws {
guard let dbURL = container.configurations.first?.url else {
XCTFail("Could not find db URL")
return
}
do {
try FileManager.default.removeItem(at: dbURL)
} catch {
XCTFail("Could not delete db: \(error)")
}
}
func testRelAssignemnt_FB12363892() throws {
let group = Group(name: "Group A")
ctx.insert(group)
try! ctx.save()
let descriptor = FetchDescriptor<Group>()
let groups = try ctx.fetch(descriptor)
XCTAssertFalse(groups.isEmpty)
XCTAssertEqual(groups.count, 1)
XCTAssertTrue(groups.first?.name == "Group A")
let person = Person(name: "Willy")
person.group = group
ctx.insert(person)
try ctx.save()
}
}
Greetings!
In my application I request permission from the user to utilize iCloud.
func requestPermission() { CKContainer.default().requestApplicationPermission([.userDiscoverability]) { [weak self] returnedStatus, _ in DispatchQueue.main.async { if returnedStatus == .granted { self?.permissionStatus = true } } } }
How can I programatically ask for this permission again via a button? Sometimes a user may deny or disable this permission in error.
Thank you! :)
Hello!
I would like my users to save short videos (under 30seconds 1080p) to the public database for all other users to download and view. Is this possible? Will I run into any storage pricing with Apple if I were to pursue this as my application backend?
I am looking at other methods as well (user sharing from their private database) so I can implement video sharing.
Is this feasible and worth pursuing?
Consider the Categories class below.
Without the @Model line, Xcode has no problems.
As soon as the @Model line is added, Xcode protests that the class does not conform to Decodable or Encodable.
Apparently the @Model macro expanded macro prevents the implied boilerplate that the systems adds when the Codable protocol is added to the class.
I've filed feedback (FB12444837) for this. Does anyone have suggestions that will let me avoid the boilerplate? This is the simplest class in my schema, I've got 12 other classes with many more variables.
@Model
class Categories: Identifiable, Codable {
// MARK: Identifiable
var id: UUID { return uuidKey }
// MARK: - Properties
@Attribute(.unique) var uuidKey: UUID = UUID()
var dateCreated: Date = Date()
var dateModified: Date = Date()
var dateRealm: Date? = nil
var uuidUser: UUID = UUID()
var uuidFamily: UUID = UUID()
var myName: String = ""
}
Hi
I really don't understand.
I have a record type on CloudKit where I store some data and a corresponding entity on core data that I sync with CloudKit with a very basic routine
at some point I call this func:
func GetUserFromCoredata(userID:String)->UserEntity?
{
var fetched:[UserEntity]?=nil
let fetch = NSFetchRequest<UserEntity>(entityName:"UserEntity")
let predicate = NSPredicate(format:"TRUEPREDICATE")
fetch.predicate = predicate
fetch.affectedStores = [DBGlobals.localStore, DBGlobals.cloudStore]
do{
print("RICHIESTA FETCH UTENTI IN COREDATA")
fetched = try context.fetch(fetch)
}
catch{
fatalError("errore nel recupero dell'elenco utenti")
}
if let found = fetched
{
for el in found
{
if el.userID == userID
{
return el
}
}
}
return nil
}
As you can see nothing special. it is only a fetch made on two stores.
If I run the code 20 times 19 are good and 1 result in a fatal error with this text:
2023-06-28 17:56:49.684780+0200 xDeskApp[23313:2379150] -[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x215632f50
2023-06-28 17:56:49.712724+0200 xDeskApp[23313:2379150] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x283d88000> , -[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x215632f50 with userInfo of (null)
2023-06-28 17:56:49.974635+0200 xDeskApp[23313:2379150] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x215632f50'
*** First throw call stack:
(0x1bd4d4cb4 0x1b657c3d0 0x1bd649ab8 0x1bd4eb0e8 0x1bd551900 0x1c4c53594 0x1c4bdf848 0x1c4bdf4b0 0x1c4c81d80 0x1068fa038 0x10690b814 0x1c4c81c20 0x1c4bcef68 0x1c4bcee38 0x1c4bbe200 0x1c4bc9a78 0x1c4d3752c 0x1c4c02678 0x1c4bc86d8 0x1c4bbb9fc 0x1c4bb6b14 0x1c4cc97ec 0x104bf00b0 0x104bef860 0x104bee8f4 0x1c4f82ce8 0x1c4f82d8c 0x1c5068cac 0x1c4f1f3b0 0x1c4f11338 0x1c50689d4 0x1bd53dc04 0x1bd4ebcb4 0x1bd4eb6cc 0x1c4fcc800 0x10690b158 0x1068fa038 0x1069020b0 0x106902e28 0x10690fc74 0x21d250ddc 0x21d250b7c)
libc++abi: terminating due to uncaught exception of type NSException
(Recorded stack frame)
... and really, I can't understand.
the predicate is absolutely basic, the entity exist, here I am not syncing anything, just fetching the records in the two stores... what am I doing wrong? why 19 su 20 are good and one is catching this error?
@Model class AModel {
@Attribute(.unique) var id:String
var date:Date
var b:[BModel]
init() {
self.id = UUID().uuidString
self.date = Date()
self.b = []
}
}
@Model class BModel {
@Attribute(.unique) var id:String
var date:Date
init() {
self.id = UUID().uuidString
self.date = Date()
}
}
struct MainView: View {
@Environment(\.modelContext) private var db
@State private var a:AModel = AModel()
var body: some View {
VStack {
}
.onAppear {
a.b.append(BModel())
print(a.b)
}
}
}
// CRASH :
@Model class AModel {
@Attribute(.unique) var id:String
var date:Date
var b:[BModel]
/**
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
{
get {
_$observationRegistrar.access(self, keyPath: \.b)
return self.getValue(for: \.b)
}
set {
_$observationRegistrar.withMutation(of: self, keyPath: \.b) {
self.setValue(for: \.b, to: newValue)
}
}
}
*/
init() {
self.id = UUID().uuidString
self.date = Date()
self.b = []
}
}
@Model class BModel {
@Attribute(.unique) var id:String
var date:Date
init() {
self.id = UUID().uuidString
self.date = Date()
}
}
Not sure what I'm doing wrong here. I'm taking this opportunity to add persistence to an app that hadn't had it yet.
I followed the session advice but I get this crash when running it:
SwiftData/BackingData.swift:201: Fatal error: expected attribute to be Codable
The crash is on this line:
modelContext.insert(RentSplitDataModel())
The object being created and inserted there is simple and the compiler confirms it does conform to Codable:
https://github.com/KyLeggiero/Rent-Split-for-iOS/blob/feature/MVP/Shared/Model/RentSplitDataModel.swift
I have my app including iCloud support in the App Store for many years now. When I run the app on iOS 17 Beta 2 I am experiencing a very bad performance because the main thread seems to be blocked most of the time.
When I run the app using the Time Profiler in Instruments it also reports the hangs and the busy main thread.
I looked into the profiler window to see methods with long runtime. The most prominent method was:
[BRQuery itemCollectionGathererDidReceiveUpdates:deleteItemsWithIDs:] coming from "CloudDocs". That seems to be some iOS internal class.
I do not really know where to look next and I want to know whether somebody of you also experienced a similar problem?
Thanks,
Dirk