0

I'm trying to create a simple ToDo App for practice. I created a DataModel for struct Task and tried to use it to iterate in a List in a NavigationView. When I write code like this, it works fine.

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            List(DataModel.data, id: \.id) { object in
                HStack {
                    object.finished == true ?
                    Label(object.description, systemImage: "checkmark.circle") :
                    Label(object.description, systemImage: "circle")
                }
            }
        }
    }
}

I see the UI being rendered like this.

Expected UI

However, when I move the HStack into a custom view called TaskView, I'm getting multiple errors on lines NavigationView and List. The errors are as follows.

Conflicting arguments to generic parameter 'Content' ('<<hole>>' vs. '<<hole>>' vs. '<<hole>>' vs. '<<hole>>')

Conflicting arguments to generic parameter 'Content' ('NavigationView<<<hole>>>' vs. 'NavigationView<<<hole>>>')

Conflicting arguments to generic parameter 'Content' ('ForEach<[Task], Int, <<hole>>>' vs. 'ForEach<[Task], Int, <<hole>>>' vs. 'ForEach<[Task], Int, <<hole>>>' vs. 'ForEach<[Task], Int, <<hole>>>')

Conflicting arguments to generic parameter 'Content' ('List<Never, ForEach<[Task], Int, <<hole>>>>' vs. 'List<Never, ForEach<[Task], Int, <<hole>>>>')

Conflicting arguments to generic parameter 'RowContent' ('<<hole>>' vs. '<<hole>>')

Here is the source code for both the ContentView and TaskView in failing case.

ContentView.swift

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            List(DataModel.data, id: \.id) { object in
                TaskView(finished: object.finished, description: object.description)
            }
        }
    }
}

TaskView.swift

import SwiftUI

struct TaskView: View {
    
    @Binding var finished: Bool
    @Binding var description: String
    
    var body: some View {
        HStack {
            finished == true ?
                Label(description, systemImage: "checkmark.circle") :
                Label(description, systemImage: "circle")
        }
    }
}

struct TaskView_Previews: PreviewProvider {
    
    @State static var finished = false
    @State static var description = "Persimmons"
    
    static var previews: some View {
        TaskView(finished: $finished, description: $description)
    }
}

DataModel.swift

import UIKit

struct MyTask: Hashable {
    var id: Int
    var finished: Bool
    var description: String
}

class DataModel: NSObject {
    static let data: [MyTask] = [
        MyTask(id: 0, finished: false, description: "Onions"),
        MyTask(id: 1, finished: true, description: "Tomatoes"),
        MyTask(id: 2, finished: false, description: "Persimmons"),
        MyTask(id: 3, finished: false, description: "Pasta")
    ]
}

Can any one tell me why I'm getting this error and how to resolve this error and what is the right way to create a CustomView?

Update

Following change to TaskView seems to have done the trick. Removing @Binding resolved the errors and the UI is rendered. However, not sure how the changes to datamodel are propagated in that case, but that is for another time.

struct TaskView: View {
    
    var finished: Bool
    var description: String
    
    var body: some View {
        HStack {
            finished == true ?
            Label(description, systemImage: "checkmark.circle").foregroundColor(Color.gray) :
                Label(description, systemImage: "circle").foregroundColor(Color.black)
        }.padding(.leading).padding(.bottom)
        .frame(maxWidth: .infinity, alignment: .leading)
    }
}
Buddha
  • 4,339
  • 2
  • 27
  • 51
  • Cannot reproduce. How is `DataModel.data` declared? – Sweeper Jun 05 '23 at 06:04
  • 1
    Usually you don't need to put binding to subview like this. – andylee Jun 05 '23 at 06:18
  • 1
    You shouldn’t use @Binding since you are not modifying the properties so just declare them as `let`. And if you do want to modify them then you must most likely change DataModel – Joakim Danielson Jun 05 '23 at 06:20
  • Note, Swift has already a `Task` defined. I suggest you use another name for your own `Task` object, eg, `MyTask` so as not to confuse yourself and the compiler. – workingdog support Ukraine Jun 05 '23 at 06:22
  • Added `DataModel` code also, Changing the variables to let in TaskView seems to have worked. – Buddha Jun 05 '23 at 07:39
  • @JoakimDanielson, Thanks your suggestion to remove `@Binding` seems to have removed the errors, however, how would I handle if I want to modify them? – Buddha Jun 05 '23 at 07:50
  • 1
    Have a look at this link, it gives you some good examples of how to manage data in your app [Managing model data in your app](https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app) – workingdog support Ukraine Jun 05 '23 at 07:56
  • 1
    Use “switch” or “if else” not a ternary operation – lorem ipsum Jun 05 '23 at 11:41

2 Answers2

0

Based on the the comments, following change to TaskView seems to have done the trick. Removing @Binding resolved the errors and the UI is rendered.

struct TaskView: View {
    
    var finished: Bool
    var description: String
    
    var body: some View {
        HStack {
            finished == true ?
            Label(description, systemImage: "checkmark.circle").foregroundColor(Color.gray) :
                Label(description, systemImage: "circle").foregroundColor(Color.black)
        }.padding(.leading).padding(.bottom)
        .frame(maxWidth: .infinity, alignment: .leading)
    }
}
Buddha
  • 4,339
  • 2
  • 27
  • 51
0
    .sheet(isPresented: $isShowsLikes) {
        NavigationView {
            List(likeVM.postLikes) { like in
                NavigationLink(
                    destination: NavigateProfileView(isInProfile: $isInProfile, id: post.userid, username: post.username),
                    label: {
                        Text(like.username)
                    }
                )
            }
            .listStyle(.plain)
            .padding()
        }
    }

I solve my problem with this. A little bit different but using binding in List and inside the NavigationLink was given me same error. With this navigationLink usage i fixed it.