0

I'm working on a SwiftUI app that makes use of Core Data. I have a list of exercises as entities and I have a List in which every exercise can be marked as favorite using a swipe action:

struct ExerciseListView: View {
    @Environment(\.managedObjectContext) private var viewContext
    
    private var fetchRequest: FetchRequest<Exercise>
    private var exerciseList: FetchedResults<Exercise> { return fetchRequest.wrappedValue }
    private let exercises: ExerciseList
    @State private var searchText = ""
    
    init(list: ExerciseList) {
        self.exercises = list
        self.fetchRequest = Exercise.fetchExerciseInExerciseList(withListName: list.name)
    }
    
    var body: some View {
        List(exerciseList, id: \.self) { exercise in
            NavigationLink {
                ExerciseView()
                    .environmentObject(exercise)
            } label: {
                if (exercise.favorite) {
                    
                    Label(exercise.name, image: "star.fill")
                        .accentColor(.yellow)
                    
                } else {
                    Text(exercise.name)
                }
            }.swipeActions {
                Button {
                    toggleFavorite(exercise)
                } label: {
                    Label(NSLocalizedString("Favorite", comment: ""), image: "star")
                }
            }
        }
        .searchable(text: $searchText, prompt: NSLocalizedString("Search", comment: ""))
        .onChange(of: searchText, perform: { newValue in
            guard !newValue.isEmpty else {
                exerciseList.nsPredicate = nil
                return
            }
            exerciseList.nsPredicate = NSPredicate(format: "%K CONTAINS[cd] %@", argumentArray: [#keyPath(Exercise.name), newValue])
        })
        .navigationBarTitle(exercises.name)
        .navigationBarTitleDisplayMode(NavigationBarItem.TitleDisplayMode.automatic)
    }
    
    private func toggleFavorite(_ exercise: Exercise) {
        Exercise.toggleFavorite(exercise, in: viewContext)
    }
}

The toggleFavorite method looks like this:

static func toggleFavorite(_ exercise: Exercise, in context: NSManagedObjectContext) {
        exercise.favorite.toggle()
        do {
            try context.save()
        } catch  {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }

The problem I'm having is that if I execute the app in an emulator or my physical phone by hitting the run button, I can easily mark and unmark an exercise as a favourite, but if I make a release of my app and upload it to TestFlight, it just doesn't work. Is there any way I can debug the problem or maybe log what's happening?

Why could this be happening?

Thanks a lot in advance!

noloman
  • 11,411
  • 20
  • 82
  • 129
  • Just looking at this code you are not observing the changes. I’m surprised it works at all. FetchRequest is a SwiftUI wrapper that isn’t wrapped, it is missing the @ and the individual objects should be put in an ObservedObject wrapper. Watch the CoreData concurrency video from WWDC 21 you’ll see the documented uses there. – lorem ipsum Oct 26 '21 at 14:01
  • How can I put the individual object in an ObservedObject? I’ve been looking for a way to do it and I don’t know how (still a newbie with SwiftUI). Do I expose a FetchedResult o do I directly expose a Exercise (which is my entity)? Thanks for the help by the way! – noloman Oct 26 '21 at 16:36
  • @loremipsum BTW I forgot to mention I'm not using a @FetchRequest because I need to do it dynamically, and thus I'm constructing the request in the View constructor (`self.fetchRequest = Exercise.fetchExerciseInExerciseList(withListName: list.name)`. I'm not sure if I can do this in a better and different way tho – noloman Oct 26 '21 at 16:50
  • You should look at the video and follow the template. Here is a question with a dynamic https://stackoverflow.com/questions/68530633/how-to-use-a-fetchrequest-with-the-new-searchable-modifier-in-swiftui/68549693#68549693 – lorem ipsum Oct 27 '21 at 01:58
  • As far as how to wrap them just make su views and take them in as a parameter – lorem ipsum Oct 27 '21 at 01:58
  • FetchRequest is a wrapper it shouldn’t be used without the @ there are no documented uses for it without it and is not guaranteed to work – lorem ipsum Oct 27 '21 at 02:00
  • Thanks a lot for your help @loremipsum! unfortunately even when adding the @FetchRequest and moving the logic to an `ObservableObject`, it fetches all the data but it's impossible to make a search (I followed the example in the post you just linked). I will close this post and will create a new one to look for advice with my current problem. – noloman Oct 27 '21 at 12:21

0 Answers0