In JobDetail
, the issue is this line:
ForEach(keys.indices) { index in
The initializer on ForEach
that is being used here is this one:
init(_ data: Range<Int>, content: @escaping (Int) -> Content)
That’s becaise keys.indices
returns a Range<Int>
. Unfortunately, as the docs for this init tell us:
Creates an instance that computes views on demand over a given constant range.
With those last two words being the most important. You’ll notice if you look at George’s details first, then Mary’s, there will be no crash but you will only see 2 of Mary’s items. That’s because George only has 2 items and since the ForEach
is constant, it believes that whatever it’s looping through will only have 2 items.
However, keys
and values
have been recalculated now and keys.indices.count == 5
so when you try to display George—who only has 2 items—again…crash!
Same thing happens if you look at Mary first then try to look at George.
There are two things you could do to fix this issue:
- Change the
ForEach
line to this:
ForEach(keys.indices, id: \.self) { index in
This will cause SwiftUI to use a different initializer on ForEach
and the range that it loops through will be dynamic each time rather than constant.
Personally, I would not recommend this solution. It’s easiest, for sure, but it also ties each item’s id
to its index in the keys
array, which doesn’t work well if the array can have items added or removed. You could end up with a situation where you replace the item at, say, index 1 but because index 1 is the same as index 1, SwiftUI won’t recognize that the item stored at that index has changed and won’t re-render your new content to the screen.
- Add a method in your view model to return the items to loop through in a way that conforms to
Identifiable
and loop through them like that. This is where perhaps using a Set
to store the items (which would be an array in the corresponding JSON) might be a good idea. If you are storing items that are only true
or only false
, you don’t really need a Dictionary
since all the keys would have the same value.