NEW: Learn to build amazing SwiftUI apps for macOS with my new book! >>

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

Forums > SwiftUI

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()
    }
}

1      

Take a look at this: https://www.hackingwithswift.com/quick-start/swiftui/how-to-create-views-in-a-loop-using-foreach

Basically, you're ForEach needs an additional id: \.self

2      

Hi @franklan010

What you may need to do is have a struct FilterImage eg

struct FilterImage: Identifiable {
    let id = UUID()
    let image: Image
}

and then in your FilterView have

@State var filteredImages = [FilterImage]() // use plural (s)

then your ForEach can be this

 HStack{
    ForEach(filteredImages) { filtered in
        Button {

        } label: {
            filtered.image
        }
    }
}

1      

@NigelGee Thanks man it works to get rid of this error, but there is another error displayed from contentView which is "No exact matches in call to instance method 'append' ". Could you please help me on that as well? I really aapreciate!

1      

It probably to do with this

let filteredImage = Image(uiImage: uiImage)

Try

let filterImage = FilterImage(image:  Image(uiImage: uiImage))

1      

@NigelGee Awesome! Thank you so much, it works

1      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Spend less time managing in-app purchase infrastructure so you can focus on building your app. RevenueCat gives everything you need to easily implement, manage, and analyze in-app purchases and subscriptions without managing servers or writing backend code.

Get Started

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.