0

I am new to CoreData and don't understand how to write and read arrays from Firebase Realtime to CoreData.

This is what Firebase looks like: enter image description here

Here are the Entities: enter image description here enter image description here

Can you tell me how to properly get an array from Firebase into CoreData? Here is FirebaseController:

final class FirebaseController: ObservableObject {

@Published var birds = [Bird]()
@Published var places = [Place]()


private lazy var databaseDB: DatabaseReference? = {
    let reference = Database.database().reference().child("db")
    return reference
}()

private lazy var birdsDB: DatabaseReference? = {
    let reference = Database.database().reference().child("db").child("birds")
    return reference
}()

private lazy var placesDB: DatabaseReference? = {
    let reference = Database.database().reference().child("db").child("places")
    return reference
}()

private let context = PersistenceController.shared.viewContext

init() {
    listentoRealtimeDatabase()
}

func listentoRealtimeDatabase() {
    guard let dbBirds = birdsDB else {
        return
    }
    guard let dbPlaces = placesDB else {
        return
    }
    
    dbBirds
        .observe(.childAdded) { [weak self] snapshot, context in 
            guard
                let self = self,
                var json = snapshot.value as? [String: Any]
            else {
                return
            }
            json["id"] = snapshot.key
            do {
                let birdData = try JSONSerialization.data(withJSONObject: json)
                let decoder = JSONDecoder(context: self.context)
                let bird = try decoder.decode(Bird.self, from: birdData)
                
                print("success \(String(describing: bird.name!)) \           (String(describing: bird.imageURL!))")
                if !self.birds.contains(where: { $0.name == bird.name }) { 
                    self.birds.append(bird)
                    save()
                }
                print("Count: \(birds.count)")
            }
            catch { print(error)
            }
        }
    dbPlaces
        .observe(.childAdded) { [weak self] snapshot, context  in {
            guard
                let self = self,
                var json = snapshot.value as? [String: Any]
            else {
                return
            }
            json["id"] = snapshot.key
            do {
                let placeData = try JSONSerialization.data(withJSONObject: json)
                let decoder = JSONDecoder(context: self.context)
                let place = try decoder.decode(Place.self, from: placeData)
                
                print("success \(String(describing: place.id!))")
                if !self.places.contains(where: { $0.id == place.id }) { 
                    self.places.append(place)
                    print(place.placeName)
                    save()
                }
                print("Count: \(places.count)")
            }
            catch { print(error)
            }
        }
            // получаем данные из CoreData
            getBirdsFromCoreData()
            getPlacesFromCoreData()
        }
}

func getBirdsFromCoreData() {
    let request = Bird.fetchRequest()
    request.returnsObjectsAsFaults = false
    
    if let results = try? self.context.fetch(request) {
        self.birds = results
    }
}

func getPlacesFromCoreData() {
    let request = Place.fetchRequest()
    request.returnsObjectsAsFaults = false
    
    if let results = try? self.context.fetch(request) {
        self.places = results
    }
    print(places.count)
}

func stopListening() {
    databaseDB!.removeAllObservers()
}

func deleteRecord(indexSet: IndexSet) {
   
    let itemToDelete = birds[indexSet.first!]
        context.delete(itemToDelete)

    save()
    getBirdsFromCoreData()
    getPlacesFromCoreData()
    }

private func save() {
    guard context.hasChanges else { return }
    do {
        try context.save()
        print("Saved changes.")
    } catch {
        print("Could not save changes in context: \(error)")
    }
}

}

And CoreData classes: In Places it is unclear to me how to properly process the array, can you tell me how to do this?

@objc(Bird)
public class Bird: NSManagedObject, Identifiable, Codable {

enum CodingKeys: String, CodingKey {
    case imageURL
    case name
}

static let managedObjectContext = CodingUserInfoKey(rawValue: "managedObjectContext")

@nonobjc public class func fetchRequest() -> NSFetchRequest<Bird> {
    return NSFetchRequest<Bird>(entityName: "Bird")
}

@NSManaged public var id: String?
@NSManaged public var name: String?
@NSManaged public var imageURL: String?
@NSManaged public var places: NSSet?

public var birdPlases: [Place] {
    let placesSet = self.places as? Set<Place> ?? []
    
    return placesSet.sorted {
        $0.placeName > $1.placeName
    }
}

public var birdName: String {
    return name ?? ""
}

public var image: String {
    return imageURL ?? ""
}

public required convenience init(from decoder: Decoder) throws {
    guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else   { fatalError("Error: with managed object context!") }
        let entity = NSEntityDescription.entity(forEntityName: "Bird", in: context)!
        self.init(entity: entity, insertInto: context)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        imageURL = try values.decode(String.self, forKey: .imageURL)
    }

// MARK: - Encodable
public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(name, forKey: .name)
    try container.encode(imageURL, forKey: .imageURL)
 }

}

extension CodingUserInfoKey {
static let context = CodingUserInfoKey(rawValue: "context")!
}

extension JSONDecoder {
convenience init(context: NSManagedObjectContext) {
    self.init()
    self.userInfo[.context] = context
}
}

extension Bird {

@objc(addPlaceObject:)
@NSManaged public func addToPlaces(_ value: Place)

@objc(removePlaceObject:)
@NSManaged public func removeFromPlaces(_ value: Place)

@objc(addEmployees:)
@NSManaged public func addToPlaces(_ value: NSSet)

@objc(removeEmployees:)
@NSManaged public func removeFromPlaces(_ value: NSSet)

}

@objc(Place)
public class Place: NSManagedObject, Identifiable, Codable {

enum CodingKeys: String, CodingKey {
    case names
}

@nonobjc public class func fetchRequest() -> NSFetchRequest<Place> {
    return NSFetchRequest<Place>(entityName: "Place")
}

@NSManaged public var id: UUID?
@NSManaged public var names: Data?


//    public var placeName: String {
//        return name ?? ""
//    }

public required convenience init(from decoder: Decoder) throws {
    guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else  { fatalError("Error: with managed object context!") }
        let entity = NSEntityDescription.entity(forEntityName: "Place", in: context)!
        self.init(entity: entity, insertInto: context)

        let values = try decoder.container(keyedBy: CodingKeys.self)
        names = try values.decode(Data.self, forKey: .names)
    }

// MARK: - Encodable
public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(names, forKey: .names)
}
}
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
Max
  • 37
  • 7
  • “In Places it is unclear to me how to properly process the array”, could you clarify this? What is “Places”, what is “the array”? It’s hard to understand what your problem is. – Joakim Danielson Aug 03 '23 at 07:18
  • There is a names string array in Places and I don't understand how to properly create it in CoreData and get the data from Firebase. Can you explain? – Max Aug 03 '23 at 09:04
  • You can either use a Transformable property or easier convert the string array to json and store it as Data or String. https://stackoverflow.com/questions/57703836/save-array-of-strings-to-coredata – Joakim Danielson Aug 03 '23 at 10:02
  • Thank you very much, I'll try to do it – Max Aug 03 '23 at 10:23

0 Answers0