WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

Getting an error when using interpolated strings with .accessibilityLabel

Forums > 100 Days of SwiftUI

I was working through Project 15 and when I was doing the challenges of adding accessibility to old projects I kept getting an error if I passed anything other than a string literal to accessibilityLabel. The error is "The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions."

So if I had: .accessibilityLabel("Business")

It worked fine. But if I had: .accessibilityLabel("\(item.name)")

I'd get an error.

This is from iExpense and item is an ExpenseItem and the name property is a string.

2      

Here's ContentView:

struct ContentView: View {
    @StateObject var expenses = Expenses()
    @State private var showingAddExpense = false

    var body: some View {
        NavigationView {
            List {
                Section {
                    ForEach(expenses.items) { item in
                        if item.type == "Business"{
                            HStack {
                                VStack(alignment: .leading) {
                                    Text(item.name)
                                        .font(.headline)
                                    Text(item.type)
                                }

                                Spacer()
                                amountView(amount: item.amount)
                            }
                            .accessibilityLabel("\(item.name)") //error occurs here
                            .accessibilityHint("Business")
                        }
                    }
                    .onDelete(perform: removeItems)
                }

                Section {
                    ForEach(expenses.items) { item in
                        if item.type == "Personal" {
                            HStack {
                                VStack(alignment: .leading) {
                                    Text(item.name)
                                        .font(.headline)
                                    Text(item.type)
                                }

                                Spacer()
                                amountView(amount: item.amount)
                            }
                            .accessibilityLabel("\(item.name)")
                            .accessibilityHint("Personal")
                        }
                    }
                    .onDelete(perform: removeItems)
                }
            }
            .navigationTitle("iExpense")
            .toolbar {
                Button {
                    showingAddExpense = true
                } label: {
                    Image(systemName: "plus")
                }
            }
        }
        .sheet(isPresented: $showingAddExpense) {
            AddView(expenses: expenses)
        }
    }

    func removeItems(at offsets: IndexSet) {
        expenses.items.remove(atOffsets: offsets)
    }
}

struct amountView: View {
    let amount: Double
    private let currency = FloatingPointFormatStyle<Double>.Currency(code: Locale.current.currencyCode ?? "USD")

    var body: some View {
        if amount < 10.0 {
            Text(amount, format: currency)
                .foregroundColor(.green)
        } else if amount < 100.0 {
            Text(amount, format: currency)
                .foregroundColor(.yellow)
        } else {
            Text(amount, format: currency)
                .foregroundColor(.red)
        }
    }
}

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

Here's the ExpenseItem struct:

 struct ExpenseItem: Identifiable, Codable {
    var id = UUID()
    let name: String
    let type: String
    let amount: Double
}

2      

I also tried cleaning the build folder, closing/reopening the project, closing/reopening xcode and rebooting.

2      

Try to refactor the Sections out into another view

EG

struct SectionView: View {
    let expenses: Expenses
    let type: String

    var body: some View {
        ForEach(expenses.items) { item in
            if item.type == type {
                HStack {
                    VStack(alignment: .leading) {
                        Text(item.name)
                            .font(.headline)
                        Text(item.type)
                    }

                    Spacer()
                    AmountView(amount: item.amount)
                }
                .accessibilityLabel("\(item.name)")
                .accessibilityHint("\(type)")
            }
        }
        .onDelete(perform: removeItems)
    }

    func removeItems(at offsets: IndexSet) {
        expenses.items.remove(atOffsets: offsets)
    }
}

then in ContentView

struct ContentView: View {
    @StateObject var expenses = Expenses()
    @State private var showingAddExpense = false

    var body: some View {
        NavigationView {
            List {
                Section {
                    SectionView(expenses: expenses, type: "Business")
                }

                Section {
                    SectionView(expenses: expenses, type: "Personal")
                }
            }
            .navigationTitle("iExpense")
            .toolbar {
                Button {
                    showingAddExpense = true
                } label: {
                    Image(systemName: "plus")
                }
            }
        }
        .sheet(isPresented: $showingAddExpense) {
            AddView(expenses: expenses)
        }
    }
}

2      

Since item.name is already a String, did you try just using .accessibilityLabel(item.name) without the string interpolation?

And a separate note: You should really filter your expenses before you loop through them rather than having an if clause in the ForEach.

2      

@roosterboy Re: filtering, I remember I tried that but there was a problem that made it difficult to implement. I asked here about it and the best solution anyone had was using the if statements. I can't say it's elegant, I was inclined to try something like we have in C#/.NET, items.where(x => x.type == "Business"), but I couldn't find a syntactical equivalent.

2      

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.