How to sync CoreData values to a remote SQL Server

178 Views Asked by At

This is a basic Attendance app that captures TimeIn/TimeOut and saves to CoreData. Im trying to find the best approach to sync my CoreData values to a remote SQL Server. I need it to sync a small dataset at the end of each day filtered from today's date. I tried the following class, but Im really new at this. Any help would be appreciated.

These are my issues:

  1. First, Im not really sure if this is the best approach to sync the data
  2. I can't figure out how to apply a predicate in the @FetchRequest to filter CoreData for only today's values (date - datday is a String) - getting the following error: Cannot use instance member 'datDay' within property initializer; property initializers run before 'self' is available

My class code:

import Foundation
import SwiftUI

class CODataModel: ObservableObject {
    @Published var entries = [COData]()
    @Published var authenticated = ""
    
    
    @AppStorage(CurrentUserDefaults.tzone) var currentTzone: String?
    let dateFormatter = DateFormatter()

    
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(entity: Attendances.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Attendances.dateStamp, ascending: true)], predicate: NSPredicate(format: "datday = %@", datDay(dt: Date())))
    private var attendance: FetchedResults<Attendances>
    
    func uploadCoreData() {
        attendance.forEach { (attendance) in
            let uid = attendance.uid
            let lat = attendance.lat
            let lon = attendance.lon
            let placemark = attendance.placemark
            let timein = attendance.time_in
            let timeout = attendance.time_out
            let datday = attendance.datday
            
            do{
                auth(uid: uid!, lat: lat!, lon: lon!, placemark: placemark!, time_in: timein!, time_out: timeout!, datday: datday!)
                
            }

        }

    }


    func auth(uid: String, lat: String, lon: String, placemark: String, time_in: String, time_out: String, datday: String) {
        
        let uid: String = uid
        let lat: String = lat
        let lon: String = lon
        let placemark: String = placemark
        let time_in: String = time_in
        let time_out: String = time_out
        let datday: String = datday

        let cid: UUID = UUID()
        
        let repTimeIn: String = time_in.replacingOccurrences(of: " ", with: "+")
        let repTimeOut: String = time_out.replacingOccurrences(of: " ", with: "+")
        let repPlacemark: String = placemark.replacingOccurrences(of: " ", with: "+")
        
        guard let url = URL(string: "\(AppDefaults.endpoint_url)?uid=\(uid)&lat=\(lat)&lon=\(lon)&placemark=\(repPlacemark)&timein=\(repTimeIn)&timeout=\(repTimeOut)&datday=\(datday)&cid=\(cid)") else { return }
                                
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")


        URLSession.shared.dataTask(with: request) { (data, response, error) in

            guard let data=data else{return}

            let transData=try! JSONDecoder().decode(COData.self, from: data)

            DispatchQueue.main.async {
                
                
                self.entries = [transData]
                self.authenticated = transData.auth

                if transData.auth == "0001" {

                }

            }

        }.resume()
        

    }
    
    func datDay(dt: Date) -> String {
        self.dateFormatter.timeZone = TimeZone(identifier: currentTzone!)
        self.dateFormatter.dateFormat = "MM/dd/yyyy"
        let dte = dateFormatter.string(from: dt)
        
        return dte
    }
}
1

There are 1 best solutions below

1
Tom Harrington On

A lot of what makes a sync system good or bad depends on how the server you're using works, what it expects and requires. It also depends heavily on what you're trying to accomplish. There's no single answer-- different strategies apply for different apps and server APIs.

Your uploadCoreData() function appears to take a collection of Attendances objects and send their data to a server. That's fine if that's all you want to do. I'll assume that your upload code in auth(...) is correct because I have no way to know how your server works.

Some things your code does not address that are probably important:

  • This is a one way transfer, from app to server. That's not syncing, it's just uploading. If you only want uploading then that's fine but you said "sync" so maybe you want more.
  • You're deciding what to upload by filtering with the datday field. I don't know how you use that field, but you may want to make sure it matches up with the data the server has or needs. A date can be a good way to decide what to upload but if the date isn't right then you might accidentally miss uploading some data or else upload data multiple times. Is that important? Again, it depends on your server and your app's specific needs.
  • You probably want to check if the upload was successful, and record this somewhere so that you know what to upload next time. That might be what you're doing in the dataTask completion closure, it's hard to tell.
  • If you make this a two-way sync then you need to have some way to deal with conflicting changes. If the same object is edited on different devices, what data do you use? This can sometimes be complicated and the answer depends on what your app needs.

A couple of other general notes:

  • As Joakim mentions in a comment, you need to change the code somewhat so that it doesn't rely on SwifUI. This isn't UI at all, and it isn't (or shouldn't be) in a View, so it can't use SwiftUI.
  • In your auth() function, that first group of let statements are unnecessary. All those variables were passed in as arguments, you don't need to make new variables for them.

I'm not sure what to make of the error message about datDay. It would help if you could indicate the specific line of code where that shows up.