Hack Saw
Hack Saw

Reputation: 2781

SwiftUI: Cannot convert value of type '(Task) -> some View' to expected argument type '(_) -> _'

My goal here is to make a SwiftUI struct which makes a scrolling view of data in a sequence, where the data, and the data_view get put together inside the ScrollView.

I get the title error from this code on the ForEach line. The type of the array doesn't seem to matter, I set it to 'Any', and got the same error.

  1. If said in an English sentence, what is "(_) -> _"? "A function taking underscore, returning underscore" doesn't make any sense.
  2. What would make this code do what I want?
  3. Is this even the best way to do this? (I'm planning on working it to make the code more general, such as making a variable for the view function, but I want to get a working thing before going farther)
import SwiftUI

protocol DatedOrPrioritizedStruct {
    var id: UUID {get}
    var priority: Float {get set} ///Priority must be set
    var start: Date? {get set} ///Could be nil. Used in conjunction with priority if set.
}

struct TimeLine : View {

    var data: [DatedOrPrioritizedStruct]

    var body: some View {
        GeometryReader { geometry in
           NavigationView {
               VStack {
                   ScrollView {
                        ForEach(self.data, id: \.self)  { item in
                                                      //^-ERROR redline here
                            TaskView(task: item).frame(minWidth: 0, idealWidth: geometry.size.width * 0.80, maxWidth: geometry.size.width, alignment: .leading)
                        }
                    }.frame(minWidth: 0, maxWidth: geometry.size.width, alignment: .leading)
                     .navigationBarTitle("Do The First Thing", displayMode: .large)
                }
            }.navigationBarHidden(true)
            .navigationBarBackButtonHidden(true)
         }
    }
}

The Task class:

public class Task: DatedOrPrioritizedStruct, Identifiable, Equatable {
    public static func == (lhs: Task, rhs: Task) -> Bool {
        return lhs.id == rhs.id
    }

    public let id = UUID()

    var title: String
    var creation: Date
    var priority: Float
    var start: Date?
    var deadline: Date?
    var completed: Date?
    var note: String?
    var recur: Double?
    var duration: TimeInterval


    public init (_ title: String) {
        self.title = title
        self.creation = Date()
        self.priority = 3.0
        self.start = nil
        self.deadline = nil
        self.completed = nil
        self.note = nil
        self.recur = nil
        self.duration = 3600.0
    }

    public init (_ title: String, priority: Float) {
        self.title = title
        self.creation = Date()
        self.priority = priority
        self.start = nil
        self.deadline = nil
        self.completed = nil
        self.note = nil
        self.recur = nil
        self.duration = TimeInterval(9 * 24 * 3600 + 3 * 3600 + 20 * 60)
    }
}

Upvotes: 0

Views: 2511

Answers (1)

RPatel99
RPatel99

Reputation: 8106

If you replace the

TaskView(task: item).frame(minWidth: 0, idealWidth: geometry.size.width * 0.80, maxWidth: geometry.size.width, alignment: .leading)

line with a simple Text("Testing"), you'll see the error change to

Protocol type 'DatedOrPrioritizedStruct' cannot conform to 'Hashable' because only concrete types can conform to protocols

You can fix this by specifying the ForEach's identifier to be \.id:

ForEach(self.data, id: \.id)  { item in
    TaskView(task: item).frame(minWidth: 0, idealWidth: geometry.size.width * 0.80, maxWidth: geometry.size.width, alignment: .leading)
}

Make sure that TaskView's task is of type DatedOrPrioritizedStruct, not Task, because since your data array contains DataOrPrioritizedStruct objects, the item in the ForEach will be a DataOrPrioritizedStruct, not a Task.

Side note: Currently, Xcode often gives irrelevant errors, like in this case, and you can try to figure out the true source by simplifying your code (which I did by putting Text("Testing") in the ForEach and commenting out the TaskView line).

Edit: To clarify, TaskView expects to receive Task type, but the ForEach iterates on an array of DataOrPrioritizedStruct, so when you pass item into TaskView there is no guarantee that the object has the data members that are unique to Task, which is why TaskView's task's type must be DataOrPrioritizedStruct, not Task.

Upvotes: 1

Related Questions