如何在CoreData中从Firebase Realtime获取数据?

How to fetch data from Firebase Realtime in CoreData?

提问人:Max 提问时间:8/3/2023 最后编辑:Joakim DanielsonMax 更新时间:8/3/2023 访问量:70

问:

我是 CoreData 的新手,不了解如何从 Firebase Realtime 到 CoreData 写入和读取数组。

Firebase 的样子是这样的:enter image description here

以下是实体:enter image description here enter image description here

你能告诉我如何正确地将数组从 Firebase 获取到 CoreData 吗? 这是 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)")
    }
}

}

和 CoreData 类: 在 Places 中,我不清楚如何正确处理数组,您能告诉我如何做到这一点吗?

@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)
}
}
swift firebase-realtime-database core-data

评论

0赞 Joakim Danielson 8/3/2023
“在某些地方,我不清楚如何正确处理数组”,你能澄清一下吗?什么是“地点”,什么是“数组”?很难理解你的问题是什么。
0赞 Max 8/3/2023
Places 中有一个名称字符串数组,我不明白如何在 CoreData 中正确创建它并从 Firebase 获取数据。你能解释一下吗?
0赞 Joakim Danielson 8/3/2023
可以使用 Transformable 属性,也可以更轻松地将字符串数组转换为 json 并将其存储为 Data 或 String。stackoverflow.com/questions/57703836/......
0赞 Max 8/3/2023
非常感谢你,我会努力做到的

答: 暂无答案