Referencing initializer 'init(_:content:)' on 'ForEach' requires that 'Image' conform to 'Identifiable'

Hi, I'm doing a practise project about Image Filter. I would like to show a horizontal scrollView at the bottom of screen which showing all filtered images, but it displayed an error when using ForEach.

Error: Referencing initializer 'init(_:content:)' on 'ForEach' requires that 'Image' conform to 'Identifiable'

Can someone help me out before Christmas?

Happy holiday! Wish all of you have a wonderful Christmas!

ContentView

import CoreImage
import CoreImage.CIFilterBuiltins
import SwiftUI

struct ContentView: View {
  @State private var showingImagePicker = false
  @State private var image: Image?
  @State private var inputImage: UIImage?
  @State private var showingFilterView = false
  @State private var filterAmount = 0.5
  @State private var filters: [CIFilter] = [
    CIFilter.sepiaTone(),
    CIFilter.vignette(),
    CIFilter.discBlur(),
    CIFilter.pixellate(),
    CIFilter.crystallize(),
    CIFilter.twirlDistortion()
  ]
   
  let context = CIContext()
   
  var body: some View {
    ZStack {
      Image("background")
        .resizable()
        .scaledToFill()
        .ignoresSafeArea(.all)
       
      VStack {
        Button {
           showingImagePicker = true
        } label: {
          VStack {
            Image(systemName: "plus.square.fill.on.square.fill")
              .resizable()
              .frame(width: 40, height: 40)
            Text("Add photo")
              .font(.title3)
          }
          .foregroundColor(.white)
        }
         
      }
    }
    .preferredColorScheme(.dark)
    .sheet(isPresented: $showingImagePicker) {
      ImagePicker(image: $inputImage)
    }
    .onChange(of: inputImage) { _ in loadImage();loadFilter()}
    .navigate(to: FilterView(image: image), when: $showingFilterView)
  }
   
  func loadImage() {
    guard let inputImage = inputImage else {return}
    image = Image(uiImage: inputImage)
    showingFilterView = true
  }
   
  func loadFilter() {
    filters.forEach { (filters) in
      guard let inputImage = inputImage else { return }
      let beginImage = CIImage(image: inputImage)
      filters.setValue(beginImage, forKey: kCIInputImageKey)
      guard let outputImage = filters.outputImage else {return}
      let cgimg = context.createCGImage(outputImage, from: outputImage.extent)
      let uiImage = UIImage(cgImage: cgimg!)
      let filteredImage = Image(uiImage: uiImage)
       
      let filterView = FilterView()
      filterView.filteredImage.append(filteredImage)
    }
  }
}

extension View {
  /// Navigate to a new view.
  /// - Parameters:
  ///  - view: View to navigate to.
  ///  - binding: Only navigates when this condition is `true`.
  func navigate<NewView: View>(to view: NewView, when binding: Binding<Bool>) -> some View {
    NavigationView {
      ZStack {
        self
          //.navigationBarTitle("")
          //.navigationBarHidden(true)

        NavigationLink(
          destination: view,
            //.navigationBarTitle(""),
            //.navigationBarHidden(true),
          isActive: binding
        ) {
          EmptyView()
        }
      }
    }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

FilterView

import SwiftUI

struct FilterView: View{
   
  @State var image: Image?
  @State var filteredImage: [Image] = []
  var body: some View {
    NavigationView{
      ZStack{
        Image("background")
          .resizable()
          .scaledToFill()
          .ignoresSafeArea(.all)
         
        VStack {
          image?
            .resizable()
            .scaledToFit()
           
          ScrollView(.horizontal, showsIndicators: false) {
            HStack{
              ForEach(filteredImage) { image in
                Button {
                   
                } label: {
                  image
                }

                 
              }
            }
          }
           
        }
      }
    }
    .toolbar {
      ToolbarItem(placement: .navigationBarTrailing) {
        Button {
          save()
        } label: {
          Image(systemName: "square.and.arrow.down")
        }

      }
    }
  }
   
  func save() {
     
  }
}

struct FilterView_Previews: PreviewProvider {
  static var previews: some View {
    FilterView()
  }
}

As you can find in the error message, each element passed to ForEach needs to conform to Identifiable (or easily provide id to identify).

You should better think Image is not a good thing to hold in an Array and use with ForEach.

One possible solutions would be holding UIImage (or CGImage) in an Array:

Something like this:

struct FilterView: View{
    
    @State var image: Image?
    let filteredUIImage: [UIImage] //<-
    var body: some View {
        NavigationView{
            ZStack{
                //...
                VStack {
                    //...
                    ScrollView(.horizontal, showsIndicators: false) {
                        HStack{
                            ForEach(filteredUIImage, id: \.self) { uiImage in //<-
                                //...
                            }
                        }
                    }
                    
                }
            }
        }
        .toolbar {
            //...
        }
    }
    
    //...
}

And creating a local variable holding a view does not make sense.

You need to update your loadFilter():

struct ContentView: View {
    //...
    
    @State var filteredUIImage: [UIImage] = [] //<-
    
    //...
    
    var body: some View {
        
        //...
        .navigate(to: FilterView(image: image, filteredUIImage: filteredUIImage), when: $showingFilterView) //<-
    }
    
    //...
    
    func loadFilter() {
        filteredUIImage = []
        filters.forEach { (filters) in
            //...
            let uiImage = UIImage(cgImage: cgimg!)
            //let filteredImage = Image(uiImage: uiImage)

            //Creating a view as local variable does not make sense
//            let filterView = FilterView()
//            filterView.filteredImage.append(filteredImage)
            filteredUIImage.append(uiImage)
        }
    }
}

I'm not sure if this is the best solution for your purpose, generally having many images in an array would not be recommended.

Referencing initializer 'init(_:content:)' on 'ForEach' requires that 'Image' conform to 'Identifiable'
 
 
Q