Search code examples
xcodeswiftuinspredicate

Xcode Coredata: Fetch two values from one CoreData entity and insert to another CoreData entity within loop function


Im very new with CoreData fetching/display and so far able to save into CoreData from a JSON fetch.

The fetched data is an array of Airport info with only three items; airport_code, access_point and image_url.

I need to add two more values to each fetched item - a lat and lon coordinate which is stored in another CoreData entity with a matching airport_code item/attribute.

Can anyone provide some guidance as to how to create a separate function to query this other CoreData during the loop sequence by using the predicate value of the airport_code? I have attached the code I have so far:

    func saveData(context: NSManagedObjectContext){


        xArray.forEach { (data) in
            
            let entity = Airports(context: context)
            entity.airport_code = data.airport_code
            entity.access_points = data.access_points
            entity.image_url = data.image_url
            entity.lat = getLat()
            entity.lon = getLon()
        }
        
        do{
            try context.save()
            print("Success Saving to CoreData: \(xArray.count)")
        }
        catch{
            print("Error Saving to CoreData \(error.localizedDescription)")
        }
    }
    
    
    func getLat() -> String {
        @FetchRequest(entity: AllAirports.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \AllAirports.airport_code, ascending: true)])
        var results: FetchedResults<AllAirports>
        //this is where Im lost as to how to query this CoreData to fetch the LON value when there is a match to the data.airport_code in the loop above.
        
        return latResults
    }

    func getLon() -> String {
        @FetchRequest(entity: AllAirports.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \AllAirports.airport_code, ascending: true)])
        var results: FetchedResults<AllAirports>
        //this is where Im lost as to how to query this CoreData to fetch the LON value when there is a match to the data.airport_code in the loop above.
        
        return lonResults
    }



func fetchData(context: NSManagedObjectContext) {
// this function performs a JSON parse and returns the xArray above
….

Solution

  • First you want to take a look at the response here What is the best way to do a fetch request in CoreData? to get an idea how a programmatic fetch request may look like.

    As I understand your problem now, you want to write two methods getLat() and getLon() which are going to fetch the coordinates for an airport.

    I would recommend to write a single function as shown below which looks up your airport in AllAirports using the given code and returns the tuple with the coordinates found.

    func getCoord(airport_code: String) -> (lon: Double, lat: Double)? {
        let request: NSFetchRequest<AllAirports> = AllAirports.fetchRequest()
        request.predicate = NSPredicate(format: "airport_code == %@", airport_code)
    
        if let result = try? viewContext.fetch(request) {
            print("Found \(result.count) airports matching \(airport_code)")
    
            // Just return the first matched airport
            if let first = result.first {
                return (first.longitude, first.latitude)
            }
        }
    
        return nil
    }
    

    A better solution would be to add an extension to you AllAirports which returns an entry for a given (hopefully unique!) airport_code:

    extension AllAirports {
        static func airport(byCode airportCode: String, in context: NSManagedObjectContext) -> AllAirports? {
            let request: NSFetchRequest<AllAirports> = fetchRequest()
            request.predicate = NSPredicate(format: "airport_code == %@", airportCode)
    
            if let result = try? context.fetch(request) {
                return result.first
            }
            return nil
        }
    }
    

    This could then be used in your code as follows:

        func saveData(context: NSManagedObjectContext){
            xArray.forEach { (data) in
                
                let entity = Airports(context: context)
                entity.airport_code = data.airport_code
                entity.access_points = data.access_points
                entity.image_url = data.image_url
                if let airport = AllAirports.airport(byCode: data.airport_code, in: context) {
                    entity.lat = airport.latitude
                    entity.lon = airport.longitude
                }
            }