7

I'm populating a List with a Realm Result set.

When navigating from this list it opens a new view then automatically closes that view.

Using a struct presents no issue.

Why would the second view automatically close?

I have a screen recording but cant post here.

import SwiftUI
import Combine

struct TestStruct:Identifiable{

    let id = UUID()
    let firstname: String
}

extension TestStruct {
    static func all() -> [TestStruct]{
        return[
            TestStruct(firstname: "Joe"),
            TestStruct(firstname: "Jane"),
            TestStruct(firstname: "Johns")
        ]
    }
}

struct TestListView: View {
    let realmList = Horoscope.getHoroscopes() //Fetches from Realm
    let structList = TestStruct.all()

    var body: some View {
        NavigationView{
            // This owrks
            //            List(structList) { item in
            //                MyItemRow(itemTxt: item.firstname)
            //            }

            //This automatically closes the view
            List(realmList) { item in
                MyItemRow(itemTxt: item.firstname)
            }
            .navigationBarTitle("Charts", displayMode: .automatic)
            .navigationBarItems(trailing: EditButton())
        }
    }
}


struct MyItemRow: View {

    var itemTxt:String

    var body: some View {
        NavigationLink(destination: Text("Test")) {
            Text(itemTxt)
        }
    }
}

struct TestListView_Previews: PreviewProvider {
    static var previews: some View {
        TestListView()
    }
}
Yarm
  • 1,178
  • 4
  • 16
  • 29
  • You have little to no error checking here so *item.firstname* could be nil, realmList could be empty. Also, I believe NavigationLink needs to be embedded in a NavigationView. – Jay Oct 14 '19 at 19:46
  • `TestStruct.firstname` cannot be nil, it's not an optional. Empty lists are fine with `List` and `ForEach`. The `NavigationLink` is inside `MyItemRow` which is embedded in a `NavigationView` in `TestListView`. – gujci Oct 14 '19 at 20:13
  • Good points. I was more referring to this `let realmList = Horoscope.getHoroscopes()` but everything else you pointed out is correct. – Jay Oct 15 '19 at 17:32

2 Answers2

4

I think the answer can be found here

In short, do not generate the id of the collection on which the ForEach iterates. It would detect a change and navigate back.

Realm object has an auto generated id property with each reference, try replacing it with a consistent id

gujci
  • 1,238
  • 13
  • 21
  • 1
    If any observed object changes in swiftUI the constructor of the `View` runs again (at least logically), which means all computed properties are generated again, thus resulting in an array with different `id`-s. Such event wont occur in Apples tutorials since they are quite simple. If you have a `Realm` objects in a list and you alter (modify in a write block) one, and you are prepared for change, so your `objectWillChange`-gets called, the result would be a back navigation if you used the `ForEach` with the `Identifiable` `Elements` constructor. Also, please check out the issue I have linked. – gujci Oct 14 '19 at 19:49
  • ps.: `ForEach` and `List` behaves similarly with `Identifiable` collections. I mentioned `ForEach` the issue mentions `List`. – gujci Oct 14 '19 at 19:53
  • @gujci - Thanks! - List or ForEach poses the same problem. Adding a getter in the Ream-based object fixed this. var id: UUID {get { return UUID(uuidString: horoscopeId)!} } – Yarm Oct 14 '19 at 21:00
  • hi @Yarm, I added a getter to my id var like you but the problem is still there. What else have you done? – user3051673 Apr 01 '20 at 07:12
0

The following solution worked for me.

The code with an issue (specifying id: \.self is the root cause since it uses the hash calculated from all objects the Stream object consists of, including the data that lies in a subarray).

...
List(streams, id: \.self) { stream in
...

The code with no issues:

...
List(streams, id: \._id) { stream in

// or even List(streams) { stream in
...

The streams is a @ObservedResults(Stream.self) var streams and the object scheme is:

final class Stream: Object, ObjectKeyIdentifiable {
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var title: String
    @Persisted var subtitle: String?
    
    @Persisted var topics = RealmSwift.List<Topic>()

    // tags, etc.
}

The issue happened when I added new topic at the topics list in the first stack of the navigationView.