3

I am not able to bind the bookName from my Core Data object to a TextField inside a ForEach loop. How can I get this binding to work? I want the bookName value to be saved to Core Data when it changes.

I am receiving an error that says: Cannot find $book in scope.

extension Book: Identifiable {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Book> {
        return NSFetchRequest<Book>(entityName: "Book")
    }
    
    @NSManaged public var id: UUID?
    @NSManaged public var bookName: String?
    
    var wrappedBookName: String {
        bookName ?? ""
    }
}

struct BookListView: View {
    @FetchRequest(entity: Book.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Book.rankNumber, ascending: false)]) var books: FetchedResults<Book>
    
    var body: some View {
        ForEach(books) { book in
            TextField("Book Name", text: $book.bookName)  //Error: cannot find $book in scope
        }
    }
}

1 Answer 1

6

I love CoreData with SwiftUI. It works just so simple. Just create a new edit view with ObservedObject of Book.

struct EditView : View {
    @ObservedObject var book: Book
    
    init(book: Book) {
        self.book = book
    }
    
    var body : some View {
        TextField("Name", text: $book.bookName)
    }
}

And that's it. Then you can send $book.bookName as Binding to the String.

However, make sure! you have declared bookName as non-optional value in CoreData. TextField requires a Binding<String>, NOT a Binding<String?>

Use that EditView inside your ForEach and you are ready to go:

ForEach(books) { book in
    EditView(book: book)
Sign up to request clarification or add additional context in comments.

2 Comments

Just tried changing a field to non-optional and set the default text to something or empty string (in the property inspector for the Core Data attribute). Still seeing the Binding<String?> conversion error. Did a clean build and quit Xcode (13.2.1) too. It's as if the View still thinks the Core Data definitions haven't been updated. Only solution so far is to use this unwrapping technique. stackoverflow.com/questions/68543882/…
another solution is to do this TextField("Name", text: Binding($book.bookName)!)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.