The app I'm working on aims to show its users one unique Item per day. The Item has an associated ItemText and ItemImage. All Items are created when the user installs the app (see the create() function below).
The app uses SwiftData for persistence and should sync between user devices using iCloud.
Currently, when viewing past Items, there are multiple ones per day - with different content (image and text).
Is it possible to enfore one-item-per-day in iCloud and if so, how? Alternatively, how do I deduplicate the returned CKRecords before showing them in the UI? I have created such a function in a separate CloudKitService class, but am not sure where to execute it automatically.
Ideally, I'd like to retain the automagic link between SwiftData and CloudKit, but at the same time make sure there are no duplicates.
@Model class Item { var id: String = "" // will be set to the YYYYMMDD representation of the date var date: Date = Date.now var favourite: Bool = false @Relationship(deleteRule: .nullify) var text: ItemText? @Relationship(deleteRule: .cascade) var image: ItemImage? init(id: String, date: Date) { self.id = id self.date = date self.favourite = false } } @Model class ItemText: Codable { var id: Int = 0 @Attribute(.spotlight) var title: String = "" var summary: String = "" var link: String = "" @Relationship(deleteRule: .cascade, inverse: \Item.text) var items: [Item]? = [] init(id: Int, title: String, summary: String, link: String) { self.id = id self.title = title self.summary = summary self.link = link } } @Model class ItemImage: Codable { var id: String = "" var url: String = "" var thumbURL: String = "" var widgetImageURL: String = "" var user: String = "" var username: String = "" var colour: String = "" var blurhash: String = "" @Attribute(.externalStorage) var imageData: Data? @Attribute(.externalStorage) var thumbData: Data? @Attribute(.externalStorage) var widgetImageData: Data? @Relationship(deleteRule: .nullify, inverse: \Item.image) var items: [Item]? = [] public init(id: String, url: String, thumbURL: String, widgetImageURL: String, user: String, username: String, colour: String, blurhash: String) { self.id = id self.url = url self.thumbURL = thumbURL self.widgetImageURL = widgetImageURL self.user = user self.username = username self.colour = colour self.blurhash = blurhash } } @ModelActor actor ItemService { private var context: ModelContext { modelExecutor.modelContext } private let cal = Calendar.current private let imageParams = "&fm=avif&h=\(Int(SGConvenience.deviceHeight) * 3)" private let thumbParams = "&fm=avif&w=200" private let widgetParams = "&fm=jpg&q=80&w=800" private func create(texts: [ItemText], images: [ItemImage], startDate: Date) { guard images.count >= texts.count else { print("Not enough images: [\(images.count)], texts: [\(texts.count)]") return } /// Create objects and insert for (index, text) in texts.enumerated() { let date = cal.date(byAdding: .day, value: index, to: startDate) ?? .now let id = date.yearMonthDay let image = images[index] let newText = ItemText(id: text.id, title: text.title, summary: text.summary, link: text.link) context.insert(newText) let newItem = Item(id: id, date: date) newText.items?.append(newItem) let newImage = ItemImage( id: image.id, url: image.url + imageParams, thumbURL: image.url + thumbParams, widgetImageURL: image.url + widgetParams, user: image.user, username: image.username, colour: image.colour, blurhash: image.blurhash ) context.insert(newImage) newImage.items?.append(newItem) } try? context.save() } }
idproperties, any strange values or anything in the logs?