iosswiftdictionaryswiftui

Dictionary causes weird errors swift/swiftui


I have a dictionary defined as the following:

@State var instructorNamesDictionary: [String: [String]] = [:]

Content is added to the dictionary in a .task later:

for course in courses {
    var updatedinstructors: [InstructorModel] = []
    for instructorID in course.instructors {
        let instructor = try await getInstructor(uid: instructorID)
        updatedinstructors.append(contentsOf: instructor)
        
        for names in updatedinstructors {
            instructorNamesDictionary[instructorID] = [names.name]
        }
    }
}

Afterwards, I try to use this dictionary into a struct called CourseCard that takes in some parameters:

struct CoursesCard: View {
    var name: String
    var image: Image
    var youtubeLinks: [String]
    var description: String
    var instructors: [String]
    var labels: [String]
    var isFree: Bool
    var ispro: Bool

    // Rest of design code

}

Now when I do a ForEach loop on another array through:

ForEach(basicCourses) { course in
    let image = images[course.image_ref] ?? Image("noImage")
    
    CoursesCard(
        name: course.Name,
        image: image,
        youtubeLinks: course.youtube_videos,
        description: course.Description,
        instructors: instructorNamesDictionary[
            ForEach(course.instructors) { instruc in instruc }
        ] ?? [
            "No instructor"
        ],
        labels: course.labels,
        isFree: course.isfree,
        ispro: isPro
    )
}

This gives me:

Cannot convert value 'basicCourses' of type '[CourseModel]' to expected type 'Binding<[CourseModel]>', use wrapper instead

However if I pass another array, no error is given.

Here is CourseModel and InstructorModel if needed:

struct CourseModel: Decodable,Identifiable {
    let id: String
    let Name: String
    let Description: String
    let image_ref: String
    let youtube_videos: [String]
    let labels: [String]
    let instructors: [String]
    let isfree: Bool

    enum CodingKeys: String, CodingKey {
        case id
        case Name
        case Description
        case image_ref
        case youtube_videos
        case labels
        case instructors
        case isfree
    }
}


struct InstructorModel: Decodable,Identifiable {
    let id: String
    let name: String
    
    enum CodingKeys: String, CodingKey {
        case id
        case name
    }
}

I tried to change the ForEach loop into:

ForEach($basicCourses) { $course in
    let image = images[course.image_ref] ?? Image("noImage")
    
    CoursesCard(
        name: course.Name,
        image: image,
        youtubeLinks: course.youtube_videos,
        description: course.Description,
        instructors: instructorNamesDictionary[
            ForEach(course.instructors) { instruc in instruc }
        ] ?? [
            "No instructor"
        ],
        labels: course.labels,
        isFree: course.isfree,
        ispro: isPro
    )
}

But that just throws out other errors.


Solution

  • You should extract the instructor names outside the CoursesCard initializer and pass them as an array of strings.

    ForEach(basicCourses) { course in
        let image = images[course.image_ref] ?? Image("noImage")
        
        let instructorNames = course.instructors.compactMap { instructorID in
            instructorNamesDictionary[instructorID]?.first ?? "No Instructor"
        }
        
        CoursesCard(
            name: course.Name,
            image: image,
            youtubeLinks: course.youtube_videos,
            description: course.Description,
            instructors: instructorNames,
            labels: course.labels,
            isFree: course.isfree,
            ispro: isPro
        )
    }