Post

Replies

Boosts

Views

Activity

Undo in SwiftData deletes all data at once.
When the following models in SwiftData, @Model final class UndoRedoData { var id: [Int] init(id: [Int]) { self.id = id } } I created the following code. struct ContentView: View { @ObservedObject var swiftDataViewModel = SwiftDataArrayViewModel.shared @State private var idArray: [Int] = [1,2,3,4] @State private var firstviewSwich: Bool = true @State private var twoviewSwich: Bool = false @State private var threeviewSwich: Bool = false var body: some View { VStack { if firstviewSwich == true { Button(action: addItem) { Text("1.New Item") } } if twoviewSwich == true { Button { forArrayData() } label: { Text("2.Data Road") } } if threeviewSwich == true { Button(action: undoItem) { Text("3.Undo") } } } } private func addItem() { withAnimation { let newItem = UndoRedoData(id: [1,2,3,4]) swiftDataViewModel.taskContext.insert(newItem) do { try swiftDataViewModel.taskContext.save() } catch { print(error) } swiftDataViewModel.fetchItems() firstviewSwich.toggle() twoviewSwich.toggle() } } private func forArrayData() { twoviewSwich.toggle() for data in idArray { swiftDataViewModel.idUndoCreate(id: data, undoManager: swiftDataViewModel.arrayItemUndoManager) } threeviewSwich.toggle() } private func undoItem() { swiftDataViewModel.arrayItemUndoManager.undo() threeviewSwich.toggle() firstviewSwich.toggle() } } class SwiftDataArrayViewModel: ObservableObject { static let shared = SwiftDataArrayViewModel() let modelContainer: ModelContainer @ObservationIgnored lazy var taskContext: ModelContext = { return ModelContext(modelContainer) }() @Published var arrayItems = [UndoRedoData]() @Published var arrayItemUndoManager = UndoManager() init() { let schema = Schema([UndoRedoData.self]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { modelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError(error) } fetchItems() } func fetchItems() { let fetchDescriptor = FetchDescriptor<UndoRedoData>() do { arrayItems = try taskContext.fetch(fetchDescriptor) } catch { fatalError(error) } } func idUndoCreate(id: Int, undoManager: UndoManager?) { undoManager?.registerUndo(withTarget: self) { target in target.removeID() } } func removeID() { if let firstUndoRedoData = arrayItems.first { print("Before Delete:\(firstUndoRedoData.id)") if !firstUndoRedoData.id.isEmpty { firstUndoRedoData.id.removeLast() } print("After Delete:\(firstUndoRedoData.id)") } do { try taskContext.save() } catch { print(error) } fetchItems() } } In this code, 1. Create an Item in New Item, 2. Execute Data Road and register the data in the array that is the same value as the data created in New Item in SwiftData one by one in UndoManager by for data in idArray. This is done because the data in the array and the data created by New Item in SwiftData can be known in advance. private func forArrayData() { twoviewSwich.toggle() for data in idArray { swiftDataViewModel.idUndoCreate(id: data, undoManager: swiftDataViewModel.arrayItemUndoManager) } // class SwiftDataArrayViewModel: ObservableObject func idUndoCreate(id: Int, undoManager: UndoManager?) { undoManager?.registerUndo(withTarget: self) { target in target.removeID() } } After registering in UndoManager, when Undo is executed with 3. Undo, instead of being able to perform Undo where one id is deleted each time, all the data of the id in SwiftData is deleted in a one-time Undo. I would like to be able to delete one id each time Undo is performed and restore them in sequence, but I can only delete them all once. Does this mean that such registration to UndoManager should not be done with for statements, etc.? Or is there another problem in the code? I want to make sure that one id is deleted for each Undo executed.
1
0
638
Dec ’24
Is it possible to track history using HistoryDescriptor in SwiftData?
Is it possible to track history using the new HistoryDescriptor feature in SwiftData? Or can I only get the current most recent data? Or is it possible to output the changed data itself, along with timestamps? I am hoping that it is possible to track by a standard feature like NSPersistentHistoryTransaction in CoreData. Do we still have to use a method in SwiftData that creates more tracking data itself?
4
0
961
Sep ’24
How can I perform Undo&Redo when the Observable class has a SwiftData Model?

I am writing code to be able to perform Undo&Redo with SwiftUI and SwiftData. Unlike usual, there is a Model of SwiftData in the Observable class, #Preview { ContentView() .modelContainer(for: Item.self, inMemory: true, isUndoEnabled: true) @Environment(\.undoManager) var undoManager but it doesn't work. How should I describe the isUndoEnabled: true option and the undoManager? import SwiftData @Observable class SwiftDataCoordinator { static let shared = SwiftDataCoordinator() var items = [Item]() let modelContainer: ModelContainer = { let schema = Schema([ Item.self ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() }
1
0
761
Mar ’24
Is it possible to do something with @Observable class to make it constantly monitored and updatable?
Using SwiftUI, the timecode (seconds notation) has been referenced using ObservableObject as follows. In this case, the timecode values were reflected in Text in real time without any problem. struct ContentView: View { . . . var body: some View { NavigationStack { // Time Code Text Text(String(format:"%02d:%02d:%02d", sMinute, sSecond, sMsec)) .font(Font(UIFont.monospacedDigitSystemFont(ofSize: 30.0, weight: .regular))) class ViewModel: ObservableObject { // Time Code "%02d:%02d:%02d" @Published var sMinute = 0 @Published var sSecond = 0 @Published var sMsec = 0 When I changed it to @Observable class as follows, the timecode operation is stopped and the values are updated only when the operation is finished. @Observable class ViewModel { // Time Code "%02d:%02d:%02d" var sMinute = 0 var sSecond = 0 var sMsec = 0 Is it possible to do something with the @Observable class that would allow it to be constantly monitored and updated in real time? Or should we change it back? If we have a history of changing to @Observable in relation to other functions, and we have no choice but to revert back, is this where we need to make a change that would keep it functional separately?
3
0
785
Mar ’24
I want to pass array data from Swift to Metal's fragment shader in Uniform
I am trying to pass array data in Uniform from Swift to Metal's fragment shader. I am able to pass normal Float numbers that are not arrays with no problem. The structure is as follows struct Uniforms { var test: [Float] } The values are as follows let floatArray: [Float] = [0.5] As usual, we are going to write and pass the following As mentioned above, normal Float values can be passed without any problem. commandEncoder.setFragmentBytes(&uniforms, length: MemoryLayout<Uniforms>.stride, index: 0) The shader side should be as follows 
// uniform struct Uniforms { float test[1]; }; Fragment Shader // in fragment shader float testColor = 1.0; // for statement for (int i = 0; i < 1; i++) { testColor *= uniforms.test[i]; } float a = 1.0 - testColor; return float4(1.0,0.0,0.0,a); I thought that 0.5 in the array was passed, but no value is passed.
I think I am writing something wrong, but how should I write it?
0
0
577
Jan ’24
Creation of ModelContainer in case of transition to other views with NavigationLink
Sorry for the rudimentary question, SwiftData question.
In the case of Xcode standard sample code, @main struct SwiftDataTestProjectsApp: App { var sharedModelContainer: ModelContainer = { let schema = Schema([ Department.self,. ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { ContentView() } .modelContainer(sharedModelContainer) } } and create a ModelContainer for the Scene, #Preview { ContentView() .modelContainer(for: Item.self, inMemory: true) } However, if SwiftData is not used in the ContentView, and only if the transition is made to the other view using NavigationLink, as shown in the code below, a ModelContainer is created and a ModelContainer is specified for the ContentTwoView, If I want to specify a separate container for ContentTwoView, how should I create .modelContainer(sharedModelContainer) and specify .modelContainer(for: Item.self, inMemory: true)? Should I continue to create the ModelContainer for the Scene as before? Or is there a way to create it only for the specified View and specify it there? struct ContentView: View { var body: some View { NavigationStack { NavigationLink("ContentTwoView") { ContentTwoView()) } } } } struct ContentTwoView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item]. var body: some View {
1
0
816
Sep ’23
I want to display the results of a search in SwiftData and replace the data.
Sorry for the elementary question.
In the following case in SwiftData, can I display the results of the search and replace text = "Test" with text = "Test2"? // Serch let test = #Predicate<GroupItem> { testitem in testitem.text.contains("Test") } I'm having trouble understanding the database because I can't replace the data that I searched for to see if the search was successful or not. @Model class Item { var id: Int var groupItem: [GroupItem]? init(id: Int) { self.id = id } } @Model class GroupItem { var groupId: Int var text: String init(groupId: Int, text:String) { self.groupId = groupId self.text = text } } struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item] var body: some View { NavigationSplitView { List { ForEach(items) { item in NavigationLink { Text("Item at \(item.id)") } label: { Text("\(item.id)") } } .onDelete(perform: deleteItems) } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } ToolbarItem { Button(action: serchItems) { Text("Serch") } } } } detail: { Text("Select an item") } } private func addItem() { withAnimation { let newItem = Item(id: 0 + 1) let newItem2 = GroupItem(groupId: 0 + 1, text: "Test") modelContext.insert(newItem) modelContext.insert(newItem2) } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } private func serchItems() { // Serch let test = #Predicate<GroupItem> { testitem in testitem.text.contains("Test") } } } #Preview { ContentView() .modelContainer(for: Item.self, inMemory: true) .modelContainer(for: GroupItem.self, inMemory: true) }
0
0
394
Sep ’23
How can I use SwiftData to insert an insert to add to an array and delete at a specified point?
How can I insert the following code into the database to add to an array in SwiftData and delete at the specified point? struct DataModel: Identifiable, Codable { var data: [[String]] } struct ContentView: View { @State var dataArray: [DataModel] = [] var body: some View { VStack { Button("Add Data") { dataArray[0].data.append(["Add Data"]) } Button("Add Data1") { dataArray[0].data[0].append(["Add Data1"]) } Button("Remove Data") { dataArray[0].data[0].remove(at: 0) }
1
0
666
Sep ’23