Search code examples
jsoncore-dataswiftui

Core Data - Favorited posts become duplicate when fetching JSON again


In my app i fetch Json entries and save it directly in CoreData. I added aditional Boolean IsFavorite (default False) to the entyti to let user mark as favorite and display it in a separate view.

So far so good, the problem is that when i fetch again to refres the content from updated json the Posts witch are alreadi favorite get doplicated.

This is how i fetch and save the data:

class JSONViewModel: ObservableObject {

    @Published var listings: [ListingModel] = []
  //  @Published var tags :[Tags] = []
    // saving Json to Core Data...
    
    func saveData(contex: NSManagedObjectContext) {
        
        listings.forEach { (data) in
            
            let entity = Listing(context: contex)
           // entity.id = Int64(data.id)
            entity.title = data.title
            entity.name = data.name
            entity.expires = data.expires
            entity.adresa = data.adresa
            entity.listingtype = data.listingtype
            entity.latitude = Double(truncating: NSNumber(value: data.latitude))
            entity.longitude = Double(truncating: NSNumber(value: data.longitude))
            entity.isFavorite = false
           
        }

        // saving all pending data at once
        
        do{
            try contex.save()             
            print("success")
        }
        catch{
            print(error.localizedDescription)
        }
    }
    
    func fetchData(context: NSManagedObjectContext){
        
        let url = "https://... my json"
        
        var request = URLRequest(url: URL(string: url)!)
        request.addValue("swiftui2.0", forHTTPHeaderField: "field")
        
        let session = URLSession(configuration: .default)
        
        session.dataTask(with: request) { (data, res, _) in
            
            guard let jsonData = data else{return}
            
            // check for errors
            
            let response = res as! HTTPURLResponse
            // checking by status code
            
            if response.statusCode == 404 {
                print("error Api Errror")
            }
            
            // fetching JSON Data ..
            do {
                let listings = try JSONDecoder().decode([ListingModel].self, from: jsonData)
                
                DispatchQueue.main.async {
                  
                    self.listings = listings
                    self.saveData(contex: context)
                }
            }
            catch {
                print(error.localizedDescription)
            }
        }
        
        
        
        .resume()
    }
}

I mark posts as favorite with this code:

 Button(action: { fetchedData!.isFavorite.toggle();
                            do {
                                try context.save()   
                            }
                            catch {
                                print(error)   
                            } }) { Image(systemName: fetchedData!.isFavorite ? "heart.circle.fill" : "heart.circle")

On the ContentView i load latest post like this:

  HStack {
                    // checkin if core data exists
                    if results.isEmpty{
                        
                        if jsonModel.listings.isEmpty{
                            
                            HStack(alignment: .center) {
                                HStack(spacing: 10) {
                                    ProgressView()
                        
                                        .progressViewStyle(CircularProgressViewStyle(tint: Color("dinamicPillsGrass")))
                                        .scaleEffect(2, anchor: .center)
                                        // fetching data
                                        .onAppear(perform: {
                                            jsonModel.fetchData(context: context)
                                            
                                    })
                                }.frame(width: UIScreen.main.bounds.width)
                            }.modifier(cardHeight())
                            
                            // when array is clear indicator appears
                            // as result data is fetched again
                        }
                        else{
                            
                            HStack(spacing: 20) {
                                
                                
                                ForEach(jsonModel.listings,id: \.self){listing in
                                    NavigationLink (destination: CardDetailView(listing: listing)) {
                                        
                                        HStack {
                                            CardViewOrizontal(listing: listing)
                                        }
                                    }.buttonStyle(PlainButtonStyle())
                                    // display fetched Json Data..
                                }
                            }
                        }
                        
                    }
                    
                    else{
                        // results.prefix(?) unde ? cata articole sa arate
                       HStack(spacing: 20) {
                        ForEach(results.prefix(10)){listing in
                               
                                NavigationLink (destination: CardDetailView(fetchedData: listing)) {
                                    
                                    HStack {
                        CardViewOrizontal(fetchedData: listing)
                                    }
                                }.buttonStyle(PlainButtonStyle())
                            }
                        }
                        .padding(.trailing, 15)
                        .padding(.leading, 15)
   
                    }
                    // update finish
                    
                }.padding(.top, 10)

And i update the data like this: Note: i also check for Internet connection.

                Button(action: {

                    // clearing data in core data..

                    if Reachability.isConnectedToNetwork() {
                      //
                        do{
                        
                            jsonModel.listings.removeAll()
**// This code is deleteing all the saved posts - also the favorite ones**                            
//                      results.forEach { (listing) in
//                                context.delete(listing)
//                                }
 
**// this code is duplicating only the favorite posts**
                            results.forEach { (listing) in

                                if  listing.isFavorite.self == false {
                                    context.delete(listing)
                                    jsonModel.listings.removeAll()
                                }
                                else {
                                    jsonModel.fetchData(context: context)
                                }
                            }
                            
                            try context.save()
                        }
                        catch{
                            print(error.localizedDescription)
                        }
                        print("Network is connected")
                        self.isError = false
               
                    } else {

                        print("Network is not connected")
                        self.isError = true
                    }
 
                }, label: {
                    HStack(alignment: .center) {
                        Image(systemName: "icloud.and.arrow.down")
                            .modifier(textSectionIcon())
                        Text("Update")
                            .modifier(textSectionTagline())
                    }
                    .padding(5)
                    .padding(.trailing, 5)
                    .background(Color("blueLeading"))
                    .cornerRadius(20)
                    .modifier(shadowPills())
                }).alert(isPresented: $isError) {
                    Alert(title: Text("Network is not connected"),
                          message: Text("WiFi or Cellular not availible. You can still browse offline content!"),
                          dismissButton: .default(Text("OK")))
                }

How can i update the fetching withowt duplicating the favorited posts?


Solution

  • i have used Constrains by id and introduced:

     container.viewContext.automaticallyMergesChangesFromParent = true
            container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    

    `Now the data is unique, next issue is that the favorites are now getting wipped when i fetch agian!

    New question here: Update CoreData when fetch again from online Json