Home > OS >  Swift Accidental Infinite ForEach Loop
Swift Accidental Infinite ForEach Loop

Time:07-01

I'm trying to use a foreach loop to show multiple Elements in an [[String]] with the help of an incremented Index in a list. But when I want to generate the list the loop repeats infinity regardless of the specified loop-count.

This is my function that gets called in the loop, to return the wanted Array of Strings:

    func getPlaces (PlaceNumber: Int) -> [String]{
        
       
        if allPlaces.count - 1 >= PlaceNumber{
            
        return allPlaces[PlaceNumber]
        } else{
            
            return ["Not found",
                    "Not found",
                    "https://www.wikipedia.com",
                    "Not found",
                    "Not found"]
        }
    }

The Variable 'allPlaces' is an [[String]] and has 25 String-Arrays in it (0-24):

 let allPlaces: [[String]] =
    
    [["no sight",
      "No information",
      "https://www.wikipedia.com",
      "No information",
      "No information"],
     
     ["Tower of London",
      "The Tower of London, officially Her Majesty's Royal Palace and Fortress of the Tower of London, is a historic castle on the north bank of the River Thames in central London. It lies within the London Borough of Tower Hamlets, which is separated from the eastern edge of the square mile of the City of London by the open space known as Tower Hill. It was founded towards the end of 1066 as part of the Norman Conquest. The White Tower, which gives the entire castle its name, was built by William the Conqueror in 1078 and was a resented symbol of oppression, inflicted upon London by the new ruling elite. The castle was also used as a prison from 1100 until 1952, although that was not its primary purpose. A grand palace early in its history, it served as a royal residence.",
      "https://en.wikipedia.org/wiki/London_Bridge",
      "1066",
      "4"],

usw...

This is my view and the function to increment (I use the index to access the different Elements in the [[String]]). I thought that the loop should trigger just as often as the 'places.allPlaces'- Array count is. But it triggers infinitely. Even when I use '0...24' instead of "places.allPlaces'.

struct ListOfPlacesView: View {
    
    @StateObject var location = Location()
    @StateObject var places = Places()
    @State var index = 0
    
    var body: some View {
        NavigationView{
            List{
                ForEach (places.allPlaces, id: \.self) { _ in
                    Text(incrementIndex())
                }
            }
        }
        .navigationTitle("All Places")
    }
    
    func incrementIndex() -> String{
        index  = 1
        print(index)
        return  (places.getPlaces(PlaceNumber: index)[0])
    }
}

But when I start this, the 'print(index)' counts to infinity in the console and the view doesn't even load. When I delete the 'index = 1' the loop prints the first Element of the Array 25 times, like it should.

I don't want to include the first Element of the [[String]] in the list, that's why im starting at an index of 0 and increment first.

Do you have an idea why this occurs and how to stop the app from doing that? Or know a better way to increment? Sorry if this is described badly, ask if you can't figure out something.

CodePudding user response:

Your incrementIndex() function updates the variable @State var index. This will cause the view to re-render and in turn call the incrementIndex() again. This causes the infinite loop.

Currently, you are not using the function parameter ForEach supplies, but instead discard it by naming it _. Instead of an index, I'd suggest using the value ForEach already supplies:

ForEach(places.allPlaces, id: \.self) { place in
    Text(place[0])
}
  • Related