Fatal Error: Index Out of Range (forEach?)

Hello!

I am having trouble with a fatal error that says an index is out of range.

I believe this error has something to do with my ForEach loop and passing through the values of the ForEach to retrieve data from an array — I will copy and paste the “suspected” code below.

TabView (selection: $currentActivitiesIndex) {
                    
                    ForEach(0..<model.activitiesGalleryData.count, id: \.self) { num in
                        
                        AsyncImage(url: URL(string: model.activitiesGalleryData[num].url)) { asyncImage in
                            
                            asyncImage
                                .resizable()
                                .scaledToFill()
                                .frame(height: 250)
                                .clipped()
                                .overlay(Color.gray.opacity(0.225))
                                .tag(num)
                            
                        } placeholder: {
                            ZStack {
                                ProgressView()
                                Color.gray.opacity(0.2)
                            }
                            
                        }
                    }
                    
                }
                .tabViewStyle(PageTabViewStyle())
                .onReceive(timer) { _ in
                    withAnimation {
                        if currentActivitiesIndex < model.activitiesGalleryData.count - 1 {
                            currentActivitiesIndex = currentActivitiesIndex + 1
                        } else {
                            currentActivitiesIndex = 0
                        }
                    }
                }

Does anything there look visibly off? If more context needed, here is the project’s github repo: GitHub - KadenZheng/PhoeniKZ: University High School App. The front hub page is a bit confusing with all the images but click into the folder and everything code-wise is there :slight_smile: The code snippet above is from the SwiftUI file “ImageBar” (organized under the “Views” —> “Reusables” —> “Bars” group). Thank you very much for your help!!

Also, here is a screenshot of the error:

Hard to tell where that error is coming from. I downloaded the Xcode project from GitHub but it appears that there are some things missing to make it work.

If you want to check to see if that array is the issue then place an if statement around the ForEach like this to check that the array is not empty.

TabView (selection: $currentActivitiesIndex) {
                    
                    if model.activitiesGalleryData.count > 0 {
                        ForEach(0..<model.activitiesGalleryData.count, id: \.self) { num in

                            AsyncImage(url: URL(string: model.activitiesGalleryData[num].url)) { asyncImage in

                                asyncImage
                                    .resizable()
                                    .scaledToFill()
                                    .frame(height: 250)
                                    .clipped()
                                    .overlay(Color.gray.opacity(0.225))
                                    .tag(num)

                            } placeholder: {
                                ZStack {
                                    ProgressView()
                                    Color.gray.opacity(0.2)
                                }

                            }
                        }
                    }
                    
                }

Would that be necessary, because this would evaluate to false, and wouldn’t actually iterate through the array?
ForEach(0..<model.activitiesGalleryData.count, id:\.self){…

If the count is 0 then it wont get to the ForEach and if that’s where the problem is inside that block of code then he definitely will know.

The problem is here:

model.activitiesGalleryData[num]

You are looping through too many items.

Let’s say model.activitiesGallery contains 5 items. This ForEach:

ForEach(0..<model.activitiesGalleryData.count, id: \.self) { num in
    ...
}

will loop 6 times, 0 through 5. But the array indices are actually 0 through 4 (remember, arrays are 0-based). And so… index out of range.

You almost certainly should not be looping through model.activitiesGalleryData by index anyway, so there’s that too. Looping by index is usually not what you want to do in SwiftUI.

Isn’t the above always 1 less than the count?

Oh right, yeah it is. Sorry, I just woke up from a nap about ten minutes ago and clearly I’m not up to snuff yet.

hahahahaha… I know what it’s like. Brain fog huh?

Hi everyone, thank you for your help.

@Chris_Parker, I tried implementing your solution to check if the array was empty, such that the code looks like:

TabView (selection: $currentActivitiesIndex) {
                    
                    if model.activitiesGalleryData.count > 0 {
                        
                        ForEach(0..<model.activitiesGalleryData.count, id: \.self) { num in
                            
                            AsyncImage(url: URL(string: model.activitiesGalleryData[num].url)) { asyncImage in
                                
                                asyncImage
                                    .resizable()
                                    .scaledToFill()
                                    .frame(height: 250)
                                    .clipped()
                                    .overlay(Color.gray.opacity(0.225))
                                    .tag(num)
                                
                            } placeholder: {
                                ZStack {
                                    ProgressView()
                                    Color.gray.opacity(0.2)
                                }
                                
                            }
                        }
                    }
                    
                }

However, I am still getting the same error. I pushed the project again to GitHub if you want to see it. What was missing on GitHub that prevented it from working when you downloaded it? Maybe I can try redownloading/reuploading some things to make it work which might be more convenient…

Thanks again, everyone. I’m not sure what the bug is. Sorry for the trouble.

@BananaNinja

Hi Zaden,

Since there are missing files on the GitHub repo like Podfile and the ProjectName.xcworkspace to name just two, can you compress the entire project into a zip file and post that to either Dropbox or Google Drive. Then create a share link and post that link in a reply.

If you choose to use Google Drive then when you create the Share link, ensure that the “General Access” option is set to “Anyone with the Link” rather than “Restricted”.

Hi @Chris_Parker,

Here is the link to the zip file: https://drive.google.com/file/d/1_SO3CmWrP1eGZdlSIGvMPrATZefIRLmt/view?usp=sharing

Please let me know if this works. Thank you for your help!

@BananaNinja

Hi Kaden,

At what point when you run the code does it crash? Do I have to sign in or does the crash occur on a specific View.

I’ve been looking around the App screens without signing in and nothing has broken yet.

(edit)
Ok so I see the code where you added that if statement we were discussing so I commented that out and it still works fine as far as I can tell.

Maybe all you needed to do was clean the Build Folder with Shift + Command + K

Hi @Chris_Parker,

So I’m not too sure what you’re referring to regarding the “sign in” as I don’t have any sign in/authentication on my app. It crashes immediately when the simulator loads before the first visible screen appears even after I’ve cleaned the build folder multiple times. I’ve attached a link to a video of the crash below.

Were you able to replicate the crash or did it not work? Thanks for your help.

https://drive.google.com/file/d/1SA0jAM0BL2zj3UEQ69hW0gi4l2dfAo7e/view?usp=sharing

Hey Kaden,

It does not crash at all. Here is a video of it running.

(edit) try this on instead. The other was too big and buffering made it look rubbish.
https://drive.google.com/file/d/1ZuUug3BpnOzmRL_MrO26Nw_h1_xWCB8S/view?usp=sharing

You are better off downloading the video and watching it on your Mac. For some reason the buffering when viewed via Google Drive messes it up.

Note that the crash would have been on the view that scrolls through the images up the top but as you can see it is working fine.

Hm, okay that’s very strange. So does that mean my Xcode is just bugged in some way? Thank you for testing it!

@BananaNinja

I don’t know what the issue could be.

Try deleting the build folder altogether.

To do that, first close the project in Xcode and then switch to Finder. From the menu select Go and then Go to Folder and key in the following path:

~/Library/Developer/Xcode/DerivedData

Then tap Go.

Scroll down the list of folders in that DerivedData folder until you find the subfolder with a name that matches your project and delete it.

Re-open the project in Xcode and then do a Build Command + B.

Resume the Preview if necessary.

Hi @Chris_Parker,

I followed your instructions and deleted the build folder but when I tried resuming the preview, the same bug still happened. :frowning:

However, I tried running the app on my own iPhone as a real test device and it ran just fine… at this point, do you think it is worth just ignoring the error? I was going to publish an update to the App Store and so if it works on real devices, just not on the Simulator, do you think it’d be okay to just push the update anyway? Thank you!

@BananaNinja

What simulator were you using? It might be that you just need to reset it since it ought to work on a simulator as well as a real device. I was targeting an iPhone 14 simulator since I have Xcode 14.1

I was using the iPhone 11 Pro on iOS 15.5. I was testing different screen sizes to make sure that the UI looked well on different sizes but I wasn’t able to run it. It doesn’t work for any other simulators as well.