Posts

Post not yet marked as solved
12 Replies
3.9k Views
I'm not sure how to fix this or if it is even fixable. When I hold the back swipe gesture in my SwiftUI app it completely bugs out and the navigation gets screwed up. It works fine if I do a complete back swipe, but if I pause at any time while swiping this bug occurs.See this example gif:https://imgur.com/WqOqUlGIs there solution for this at all? I'm using a standard `NavigationView` with a `NavigationLink`.
Posted
by kdion4891.
Last updated
.
Post not yet marked as solved
6 Replies
3.2k Views
How do I list the relationships of a particular entity that is fetched?I know how to list the entries for the entity itself, but I can't figure out how to list one-to-many relationships in a List.See this code:struct TodoItemView: View { var todoList: TodoList var body: some View { VStack { Text(todoList.title!) List { ForEach(todoList.todoItems, id: \.self) {todoItem in Text(todoItem.title!) } } } } }That is producing errors and I have no clue how to fix them:Protocol type 'NSSet.Element' (aka 'Any') cannot conform to 'Hashable' because only concrete types can conform to protocolsValue of type 'NSSet.Element' (aka 'Any') has no member 'title'I've set up my TodoList entity to have a one-to-many with TodoITem. I fetch the todoList in the previous view and then pass it to this view:@Environment(\.managedObjectContext) var managedObjectContext @FetchRequest( entity: TodoList.entity(), sortDescriptors: [NSSortDescriptor(key: "order", ascending: true)] ) var todoLists: FetchedResults<TodoList> // ...more code here List { ForEach(todoLists, id: \.self) {todoList in NavigationLink(destination: TodoItemView(todoList: todoList), label: { Text(todoList.title!).foregroundColor(stringToColor(string: todoList.color!)) }) } }How do I use todoList.todoItems in a ForEach loop the same way so that I can also run CRUD operations on it as well?
Posted
by kdion4891.
Last updated
.
Post not yet marked as solved
1 Replies
2k Views
SwiftUI FetchedResult views fail to update when you navigate away from them and return.I have a simple todo list app I've created as an example. This app consists of 2 entities:- A TodoList, which can contain many TodoItem(s)- A TodoItem, which belongs to one TodoListFirst, here are my core data models:https://i.stack.imgur.com/JOsEw.pnghttps://i.stack.imgur.com/Q9tOs.pngFor the entities, I am using `Class Definition` in `CodeGen`.There are only 4 small views I am using in this example.`TodoListView`: struct TodoListView: View { @Environment(\.managedObjectContext) var managedObjectContext @FetchRequest( entity: TodoList.entity(), sortDescriptors: [] ) var todoLists: FetchedResults @State var todoListAdd: Bool = false var body: some View { NavigationView { List { ForEach(todoLists, id: \.self) { todoList in NavigationLink(destination: TodoItemView(todoList: todoList), label: { Text(todoList.title ?? "") }) } } .navigationBarTitle("Todo Lists") .navigationBarItems(trailing: Button(action: { self.todoListAdd.toggle() }, label: { Text("Add") }) .sheet(isPresented: $todoListAdd, content: { TodoListAdd().environment(\.managedObjectContext, self.managedObjectContext) }) ) } } }This simply fetches all TodoList(s) and spits them out in a list. There is a button in the navigation bar which allows for adding new todo lists.`TodoListAdd`: struct TodoListAdd: View { @Environment(\.presentationMode) var presentationMode @Environment(\.managedObjectContext) var managedObjectContext @State var todoListTitle: String = "" var body: some View { NavigationView { Form { TextField("Title", text: $todoListTitle) Button(action: { self.saveTodoList() self.presentationMode.wrappedValue.dismiss() }, label: { Text("Save") }) Button(action: { self.presentationMode.wrappedValue.dismiss() }, label: { Text("Cancel") }) } .navigationBarTitle("Add Todo List") } .navigationViewStyle(StackNavigationViewStyle()) } func saveTodoList() { let todoList = TodoList(context: managedObjectContext) todoList.title = todoListTitle do { try managedObjectContext.save() } catch { print(error) } } }This simply saves a new todo list and then dismisses the modal.`TodoItemView`: struct TodoItemView: View { @Environment(\.managedObjectContext) var managedObjectContext var todoList: TodoList @FetchRequest var todoItems: FetchedResults @State var todoItemAdd: Bool = false init(todoList: TodoList) { self.todoList = todoList self._todoItems = FetchRequest( entity: TodoItem.entity(), sortDescriptors: [], predicate: NSPredicate(format: "todoList == %@", todoList) ) } var body: some View { List { ForEach(todoItems, id: \.self) { todoItem in Button(action: { self.checkTodoItem(todoItem: todoItem) }, label: { HStack { Image(systemName: todoItem.checked ? "checkmark.circle" : "circle") Text(todoItem.title ?? "") } }) } } .navigationBarTitle(todoList.title ?? "") .navigationBarItems(trailing: Button(action: { self.todoItemAdd.toggle() }, label: { Text("Add") }) .sheet(isPresented: $todoItemAdd, content: { TodoItemAdd(todoList: self.todoList).environment(\.managedObjectContext, self.managedObjectContext) }) ) } func checkTodoItem(todoItem: TodoItem) { todoItem.checked = !todoItem.checked do { try managedObjectContext.save() } catch { print(error) } } }This view fetches all of the TodoItem(s) that belong to the TodoList that was tapped. This is where the problem is occurring. I'm not sure if it is because of my use of `init()` here, but there is a bug. When you first enter this view, you can tap a todo item in order to "check" it and the changes show up in the view immediately. However, when you navigate to a different TodoItemView for a different TodoList and back, the views no longer update when tapped. The checkmark image does not show up, and you need to leave that view and then re-enter it in order for said changes to actually appear.`TodoItemAdd`: struct TodoItemAdd: View { @Environment(\.presentationMode) var presentationMode @Environment(\.managedObjectContext) var managedObjectContext var todoList: TodoList @State var todoItemTitle: String = "" var body: some View { NavigationView { Form { TextField("Title", text: $todoItemTitle) Button(action: { self.saveTodoItem() self.presentationMode.wrappedValue.dismiss() }, label: { Text("Save") }) Button(action: { self.presentationMode.wrappedValue.dismiss() }, label: { Text("Cancel") }) } .navigationBarTitle("Add Todo Item") } .navigationViewStyle(StackNavigationViewStyle()) } func saveTodoItem() { let todoItem = TodoItem(context: managedObjectContext) todoItem.title = todoItemTitle todoItem.todoList = todoList do { try managedObjectContext.save() } catch { print(error) } } }This simply allows the user to add a new todo item.As I mentioned above, the views stop updating automatically when you leave and re-enter the TodoItemView. Here is a recording of this behaviour:https://i.imgur.com/q3ceNb1.mp4What exactly am I doing wrong here? If I'm not supposed to use `init()` because views in navigation links are initialized before they even appear, then what is the proper implementation?
Posted
by kdion4891.
Last updated
.
Post not yet marked as solved
1 Replies
815 Views
In my app I have a master `ContentView` which uses a `FetchRequest` in order to grab entities: struct ContentView: View { @Environment(\.managedObjectContext) var managedObjectContext @FetchRequest( entity: Note.entity(), sortDescriptors: [ NSSortDescriptor(key: "title", ascending: true, selector: #selector(NSString.caseInsensitiveCompare)) ] ) var notes: FetchedResultsThen I spit them out in a loop like so: NavigationView { List { ForEach(notes, id: \.self) {note in NavigationLink(destination: NoteDetailView(note: note), label: {In my `NoteDetailView`, I use the `note` to display its details: struct NoteDetailView: View { var note: NoteI also have another view which handles editing the `Note`: struct EditNoteView: View { var note: Note @Environment(\.managedObjectContext) var managedObjectContext @State var noteTitle: String = "" @State var noteType: String = "Note" @State var noteColor: String = "None"This `EditNoteView` will make changes to a `Note` then save it: func saveNote() { noteTitle = noteTitle.trimmingCharacters(in: .whitespacesAndNewlines) if (noteTitle.count > 0) { note.title = noteTitle note.type = noteType note.color = noteColor note.dateUpdated = Date() do { try managedObjectContext.save() } catch { print(error) } } }The user can open this `EditDetailView` from either the master view (`ContentView`) or the detail view (`NoteDetailView`).Now I've read up on this and it appears I have the opposite problem of some other people. Most people seem to have a problem updating the master from the detail view. When I call `EditNoteView` from the `NoteDetailView` and make changes it updates both the `ContentView` and then `NoteDetailView` with the changes perfectly.However, when I call `EditNoteView` from the `ContentView` and make changes it only updates the `ContentView` and not the `NoteDetailView`.I should mention that this is a catalyst app and I only notice this problem on devices that show the master view as a sidebar (Mac & iPad). I'm guessing it is because when I am making edits from the master view, the detail view is not "active" and therefore it doesn't think it needs to update? I'm not sure how to fix this.
Posted
by kdion4891.
Last updated
.
Post marked as solved
1 Replies
908 Views
In my Catalyst project I'd like to apply `SidebarListStyle()` to Mac only.My problem is I can't build the project, even when I check for OS. Heres an example: struct CrossList: View { #if targetEnvironment(macCatalyst) var body: some View { List { Text("Mac Test") } .listStyle(SidebarListStyle()) } #else var body: some View { List { Text("iOS Test") } } #endif }This gives me the following error when building:> 'SidebarListStyle' is unavailable in iOS
Posted
by kdion4891.
Last updated
.
Post marked as solved
1 Replies
6.0k Views
I'm just trying to save a relationship in Core Data using SwiftUI.`TodoListView`: struct TodoListView: View { @Environment(\.managedObjectContext) var managedObjectContext @FetchRequest( entity: TodoList.entity(), sortDescriptors: [NSSortDescriptor(key: "order", ascending: true)] ) var todoLists: FetchedResults<TodoList> @State var add = false @State var edit = false var body: some View { NavigationView { List { ForEach(todoLists, id: \.self) {todoList in NavigationLink(destination: TodoItemView(todoList: todoList), label: { Text(todoList.title!).foregroundColor(stringToColor(string: todoList.color!)) }) } } ...This creates navigation links for each todo list. The todo list is passed to the todo item view.`TodoItemView`: struct TodoItemView: View { @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> @Environment(\.managedObjectContext) var managedObjectContext @State var add = false var todoList: TodoList var body: some View { List { ForEach(todoList.todoItems!, id: \.self) {todoItem in Text(todoItem.title!) } } .navigationBarTitle(todoList.title!) .navigationBarItems(trailing: HStack(spacing: 15) { Button(action: { self.add = true }, label: { Image(systemName: "plus") .imageScale(.large) .foregroundColor(todoList.color == "None" ? .accentColor : .primary) }).sheet(isPresented: $add, content: { AddTodoItemView(todoList: self.todoList) .environment(\.managedObjectContext, self.managedObjectContext) }) ...This is supposed to list all of the todo items for the todo list. When you click on the plus image in the navigation bar, it loads a modal for adding a new todo item, and passes the todo list to it.I should note that `todoList.todoItems` is set up as `@NSManaged public var todoItems: [TodoItem]?` in my `TodoList` entity class. I've also set it up as a one-to-many relationship in Core Data.`AddTodoItemView`: struct AddTodoItemView: View { @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> @Environment(\.managedObjectContext) var managedObjectContext @State var title = "" var todoList: TodoList var body: some View { NavigationView { Form { Section { TextField("Title", text: $title) } Section { Button(action: { self.save() self.presentationMode.wrappedValue.dismiss() }, label: { Text("Save") }) } } .navigationBarTitle("Add Todo Item", displayMode: .inline) } } func save() { self.title = self.title.trimmingCharacters(in: .whitespaces) if (self.title.count > 0) { let todoItem = TodoItem(context: managedObjectContext) todoItem.title = self.title todoItem.order = (self.todoList.todoItems?.last?.order ?? 0) + 1 todoList.addToTodoItems(todoItem) do { try self.managedObjectContext.save() } catch { print(error) } } } ...The `save()` function here is what causes the error and crashes the app.I'm not sure I'm doing this correctly. Is this the right way to list and save a relationship? All I want to do is add the new todo item to the todo list. I'm having a hard time grasping working with relationships in SwiftUI.Here is the complete result of `print(error)`: 2019-11-09 00:02:43.989211-0500 ColorTodo4[10656:682980] [Snapshotting] Snapshotting a view (0x7ff3dfd310e0, _UIReplicantView) that has not been rendered at least once requires afterScreenUpdates:YES. 2019-11-09 00:02:57.142381-0500 ColorTodo4[10656:682980] [Snapshotting] Snapshotting a view (0x7ff3dff10a20, _UIReplicantView) that has not been rendered at least once requires afterScreenUpdates:YES. 2019-11-09 00:03:08.307765-0500 ColorTodo4[10656:682980] [Snapshotting] Snapshotting a view (0x7ff3dfd307e0, _UIReplicantView) that has not been rendered at least once requires afterScreenUpdates:YES. 2019-11-09 00:03:24.827731-0500 ColorTodo4[10656:682980] [Snapshotting] Snapshotting a view (0x7ff3dfe7ca10, _UIReplicantView) that has not been rendered at least once requires afterScreenUpdates:YES. 2019-11-09 00:03:40.275685-0500 ColorTodo4[10656:682980] [Snapshotting] Snapshotting a view (0x7ff3dfd3cb80, _UIReplicantView) that has not been rendered at least once requires afterScreenUpdates:YES. 2019-11-09 00:03:41.202375-0500 ColorTodo4[10656:682980] -[__NSCFSet objectAtIndex:]: unrecognized selector sent to instance 0x60000228d3e0 2019-11-09 00:03:41.207166-0500 ColorTodo4[10656:682980] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet objectAtIndex:]: unrecognized selector sent to instance 0x60000228d3e0' *** First throw call stack: ( 0 CoreFoundation 0x00007fff23c4f02e __exceptionPreprocess + 350 1 libobjc.A.dylib 0x00007fff50b97b20 objc_exception_throw + 48 2 CoreFoundation 0x00007fff23c6ff94 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132 3 CoreFoundation 0x00007fff23c53dac ___forwarding___ + 1436 4 CoreFoundation 0x00007fff23c55f38 _CF_forwarding_prep_0 + 120 5 libswiftCore.dylib 0x00007fff5105b79e $ss12_ArrayBufferV19_getElementSlowPathyyXlSiF + 142 6 libswiftCore.dylib 0x00007fff5105e6ea $sSayxSicir + 202 7 libswiftCore.dylib 0x00007fff5105ede8 $sSayxGSlsSly7ElementQz5IndexQzcirTW + 56 8 SwiftUI 0x00007fff2c4933a1 $s7SwiftUI7ForEachV11IDGeneratorO6makeID4data5index6offsetq_x_5IndexQzSitF + 289 9 SwiftUI 0x00007fff2c4963e1 $s7SwiftUI19DynamicContentState33_4103B39A1695DB4F1CFCE0B3FB46910FLLC4item2at6offsetAD4ItemCyxq_q0__G5IndexQz_SitF + 865 10 SwiftUI 0x00007fff2c497042 $s7SwiftUI19DynamicContentState33_4103B39A1695DB4F1CFCE0B3FB46910FLLC20fetchViewsPerElementSiSgyF + 466 11 SwiftUI 0x00007fff2c497dbc $s7SwiftUI19DynamicContentState33_4103B39A1695DB4F1CFCE0B3FB46910FLLC7viewIDsAA12_ViewList_IDV5ViewsCSgvg + 188 12 SwiftUI 0x00007fff2c49a732 $s7SwiftUI18DynamicContentList33_4103B39A1695DB4F1CFCE0B3FB46910FLLV5countSivgTm + 18 13 SwiftUI 0x00007fff2c49acb3 $s7SwiftUI18DynamicContentList33_4103B39A1695DB4F1CFCE0B3FB46910FLLVyxq_q0_GAA04ViewE0A2aFP5countSivgTWTm + 51 14 SwiftUI 0x00007fff2c504f59 $s7SwiftUI14MergedViewList33_70E71091E926A1B09B75AAEB38F5AA3FLLV7viewIDsAA01_dE3_IDV5ViewsCSgvg + 217 15 SwiftUI 0x00007fff2c601d16 $s7SwiftUI8SectionsV4from10useFootersAcA22_VariadicView_ChildrenV_SbtcfC + 70 16 SwiftUI 0x00007fff2c203ab9 $s7SwiftUI20SystemListDataSourceV_5style12minRowHeight0h6HeaderJ0ACyxGAA22_VariadicView_ChildrenV_So07UITableM5StyleV12CoreGraphics7CGFloatVSgANtcfC + 105 17 SwiftUI 0x00007fff2c203e8a $s7SwiftUI9PlainListV11BodyContentV4bodyQrvg + 506 18 SwiftUI 0x00007fff2c203f49 $s7SwiftUI9PlainListV11BodyContentVyx_qd__GAA4ViewA2aGP4body0E0QzvgTW + 9 19 SwiftUI 0x00007fff2c0613c7 $s7SwiftUI19DynamicPropertyBody33_9F92ACD17B554E8AB7D29ABB1E796415LLV6update7contexty14AttributeGraph0P7ContextVyADyxGGz_tF + 1671 20 SwiftUI 0x00007fff2c061bf0 $s7SwiftUI19DynamicPropertyBody33_9F92ACD17B554E8AB7D29ABB1E796415LLVyxG14AttributeGraph07UntypedN0AafGP7_update_5graph9attributeySv_So10AGGraphRefaSo11AGAttributeatFZTW + 32 21 AttributeGraph 0x00007fff2f8bbc69 $sTA + 25 22 AttributeGraph 0x00007fff2f8a3ac5 _ZN2AG5Graph11UpdateStack6updateEv + 1111 23 AttributeGraph 0x00007fff2f8a3d83 _ZN2AG5Graph16update_attributeEjb + 377 24 AttributeGraph 0x00007fff2f8a89a1 _ZN2AG8Subgraph6updateEj + 929 25 SwiftUI 0x00007fff2c19a4a0 $s7SwiftUI9ViewGraphC14runTransaction33_D63C4EB7F2B205694B6515509E76E98BLL2inySo10AGGraphRefa_tF + 224 26 SwiftUI 0x00007fff2c19a270 $s7SwiftUI9ViewGraphC17flushTransactionsyyFySo10AGGraphRefaXEfU_ + 256 27 SwiftUI 0x00007fff2c199f0f $s7SwiftUI9ViewGraphC17flushTransactionsyyF + 223 28 SwiftUI 0x00007fff2c19a08f $s7SwiftUI9ViewGraphC16asyncTransaction_8mutation5styleyAA0F0V_xAA01_D14Mutation_StyleOtAA0dI0RzlFyycfU_yACXEfU_ + 15 29 SwiftUI 0x00007fff2c198219 $s7SwiftUI9ViewGraphCIgg_ACytIeggr_TR03$s7a3UI9cD92C16asyncTransaction_8mutation5styleyAA0F0V_xAA01_D14Mutation_StyleOtAA0dI0RzlFyycfU_yACXEfU_Tf3nnpf_n + 9 30 SwiftUI 0x00007fff2c4e0817 $s7SwiftUI16ViewRendererHostPAAE06updateC5Graph4bodyqd__qd__AA0cG0CXE_tlF + 71 31 SwiftUI 0x00007fff2c4e07c3 $s7SwiftUI14_UIHostingViewCyqd__GAA0D13GraphDelegateA2aEP06updatedE04bodyqd__qd__AA0dE0CXE_tlFTW + 19 32 SwiftUI 0x00007fff2c19a06a $s7SwiftUI9ViewGraphC16asyncTransaction_8mutation5styleyAA0F0V_xAA01_D14Mutation_StyleOtAA0dI0RzlFyycfU_ + 122 33 SwiftUI 0x00007fff2c1b7cec $sIeg_ytIegr_TR + 12 34 SwiftUI 0x00007fff2bffc051 $sIeg_ytIegr_TRTA + 17 35 SwiftUI 0x00007fff2bffbf77 $sSo9NSRunLoopC7SwiftUIE14flushObserversyyFZ + 119 36 SwiftUI 0x00007fff2bffbef9 $sSo9NSRunLoopC7SwiftUIE11addObserveryyyycFZySo05CFRunbF3RefaSg_So0gB8ActivityVSvSgtcfU_ + 9 37 SwiftUI 0x00007fff2bffbfeb $sSo9NSRunLoopC7SwiftUIE11addObserveryyyycFZySo05CFRunbF3RefaSg_So0gB8ActivityVSvSgtcfU_To + 43 38 CoreFoundation 0x00007fff23bb1617 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23 39 CoreFoundation 0x00007fff23bac0ae __CFRunLoopDoObservers + 430 40 CoreFoundation 0x00007fff23bac72a __CFRunLoopRun + 1514 41 CoreFoundation 0x00007fff23****16 CFRunLoopRunSpecific + 438 42 GraphicsServices 0x00007fff38438bb0 GSEventRunModal + 65 43 UIKitCore 0x00007fff4784fb68 UIApplicationMain + 1621 44 ColorTodo4 0x0000000107668d2b main + 75 45 libdyld.dylib 0x00007fff51a1dc25 start + 1 46 ??? 0x0000000000000001 0x0 + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)Why is this happening and how do I fix it?
Posted
by kdion4891.
Last updated
.