At the live SwiftData Q&A session last week, this same question was asked several times. Each time the developer/moderator said this was not yet implemented and a Feedback should be submitted to request it. Mine is FB12292624.
Post
Replies
Boosts
Views
Activity
I fully expect Apple to provide this capability eventually, but after studying the headers for the @SectionedFetchRequest property wrapper, I began to wonder how hard it would be to create a package to do the same thing for Swift Data. The package README also has a link to a fully functional sample program that demonstrates the package.
This is what I came up with: https://github.com/Whiffer/swiftdata-sectionedquery
I can confirm that my original issue was fixed in beta 2 and continues to work in beta 3. Thank you Apple!
I have the same problem too. After many attempts to do a more reasonable workaround, I came up with this brut force kludge just to get past it.
@MainActor static func allRootItems() -> [Item] {
//TODO: What I wanted to do - Hopefully this will be fixed someday
// if let items = try? context.fetch(FetchDescriptor(predicate: #Predicate<Item>{ $0.parent == nil } ) )
//TODO: Very temporary workaround - Hopefully this will not be needed someday
if let items = try? context.fetch(FetchDescriptor<Item>()) {
return items.compactMap { $0.parent == nil ? $0 : nil }
} else {
return [Item]()
}
}
I was also looking for a workaround, but I think I actually came up with a workable solution. I took a completely different approach by not trying to drag and drop the PersistentModel objects themselves, but instead, dragging and dropping the PersistentIdentifier struct from a PersistentModel object. This works well because PersistentIdentifier is already Codable and it is very easy to make it Transferable. Also, a PersistentIdentifier struct can be used to retrieve its corresponding PersistentModel object from the ModelContext.
I have published a complete working sample program demonstrating this on GitHub: https://github.com/Whiffer/SwiftDataDragAndDropExample
The important concepts are:
Extend PersistentIdentifier to be Transferable and define your own contentType for it
extension PersistentIdentifier: Transferable {
public static var transferRepresentation: some TransferRepresentation {
CodableRepresentation(contentType: .persistentModelID)
}
}
Extend PersistentIdentifier with a generic convenience function to retrieve PersistentModel objects from the ModelContext
extension PersistentIdentifier {
public func persistentModel<Model>(from context: ModelContext) -> Model? where Model : PersistentModel {
return context.model(for: self) as? Model
}
}
Use PersistentIdentifier structs with the .draggable() and .dropDestination() View Modifiers
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
.draggable(item.persistentModelID)
.dropDestination(for: PersistentIdentifier.self) { persistentModelIDs, _ in
let targetItem = item // for clarification
for persistentModelID in persistentModelIDs {
if let draggedItem: Item = persistentModelID.persistentModel(from: self.modelContext) {
print("\(draggedItem.timestamp) dropped on: \(targetItem.timestamp)")
}
}
return true
}
Improved Solution
After creating my first workaround, I kept thinking about a more direct and generic solution. My ultimate solution is still based on dragging Transferrable PersistentIdentifiers, but does it internally. I have created a Swift Package that implements generic extensions to the .draggable() and .dropDestination() SwiftUI View modifiers to facilitate direct Drag and Drop operations with SwiftData PersistentModel objects.
The Package URL is: https://github.com/Whiffer/swiftdata-transferrable
A complete project that demonstrates how to use this package is available at: https://github.com/Whiffer/SampleSwiftDataTransferrable
Thanks. I was starting to think this might be the current answer. However, it would be a great future objective to make this a feature of iCloud Family Sharing.