将对象数组保存在核心数据中

发布于 2025-02-03 12:19:49 字数 681 浏览 2 评论 0原文

iOS开发的新手。在配方保存器应用程序上工作。我有一个用于配方的结构,可以容纳诸如名称,成分,说明之类的东西。然后,我有一个带有出已发表的食谱的班级食谱。我正在尝试将食谱实例保存在核心数据中,以便即使应用程序退出,也可以保存配方。我从未使用过核心数据,并且做了很多研究,但我只是不太了解。我尝试使用UserDefaults,但似乎只能与字符串,INT,BOOL等一起使用????同样,我尝试使用一些核心数据教程,因为我的某些属性是数组。另外,如果我有一种使用UserDefaults的方法,请让我知道,因为核心数据会让我感到恐惧!任何帮助将不胜感激。谢谢


struct Recipe : Codable, Identifiable {
    var id: String
    var name: String
    var ingredients: [String]
    var instructions: [String]
    var category: String
    var imageName: String
}
class RecipeStore : ObservableObject {
    @Published var recipes: [Recipe]
    init (recipes: [Recipe] = []) {
        self.recipes = recipes

    }
}

Fairly new to IOS development. Working on a Recipe keeper app. I have a struct for recipe that holds things like the name, ingredients, instructions. Then I have a class RecipeStore with a published array of Recipes. I am trying to save an instance of RecipeStore in core data so the recipes are saved even when the app is force quit. I have never used Core data and I have done a lot of research but I just don't quite understand it. I tried using userdefaults but it seems that only works with like strings, ints, bools, etc???? Also struggling with some of the core data tutorials I tried following because some of my attributes are arrays. Also if there is a way for me to use userdefaults, please let me know because core data scares me! Any help would be appreciated. Thank you


struct Recipe : Codable, Identifiable {
    var id: String
    var name: String
    var ingredients: [String]
    var instructions: [String]
    var category: String
    var imageName: String
}
class RecipeStore : ObservableObject {
    @Published var recipes: [Recipe]
    init (recipes: [Recipe] = []) {
        self.recipes = recipes

    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

泪是无色的血 2025-02-10 12:19:49

我的建议(受Joakim Danielson的启发)是将字符串数组作为JSON保存在核心数据中。好处是,可以通过谓词过滤字符串。

声明成分指令作为计算属性,以将数组转换为JSON,VICE,反之亦然,并将JSON属性声明为String

class CDRecipe : NSManagedObject {

    @NSManaged var id: String
    @NSManaged var name: String
    @NSManaged var category: String
    @NSManaged var imageName: String
    @NSManaged var ingredientJSON: String
    @NSManaged var instructionJSON: String
    
    var ingredients : [String] {
        get { decodeArray(from: \.ingredientJSON) }
        set { ingredientJSON = encodeArray(newValue) }
    }
    
    var instructions : [String] {
        get { decodeArray(from: \.instructionJSON) }
        set { instructionJSON = encodeArray(newValue) }
    }
    
    private func decodeArray(from keyPath: KeyPath<CDRecipe,String>) -> [String] {
        return (try? JSONDecoder().decode([String].self, from: Data(self[keyPath: keyPath].utf8))) ?? []
    }
    
    private func encodeArray(_ array: [String]) -> String {
        guard let data = try? JSONEncoder().encode(array) else { return "" }
        return String(data: data, encoding: .utf8)!
    }

}

My suggestion (inspired by Joakim Danielson) is to save the string arrays as JSON in Core Data. The benefit is that the string can be filtered by predicates.

Declare ingredients and instructions as computed properties to convert the arrays to JSON and vice versa and declare the JSON properties as String

class CDRecipe : NSManagedObject {

    @NSManaged var id: String
    @NSManaged var name: String
    @NSManaged var category: String
    @NSManaged var imageName: String
    @NSManaged var ingredientJSON: String
    @NSManaged var instructionJSON: String
    
    var ingredients : [String] {
        get { decodeArray(from: \.ingredientJSON) }
        set { ingredientJSON = encodeArray(newValue) }
    }
    
    var instructions : [String] {
        get { decodeArray(from: \.instructionJSON) }
        set { instructionJSON = encodeArray(newValue) }
    }
    
    private func decodeArray(from keyPath: KeyPath<CDRecipe,String>) -> [String] {
        return (try? JSONDecoder().decode([String].self, from: Data(self[keyPath: keyPath].utf8))) ?? []
    }
    
    private func encodeArray(_ array: [String]) -> String {
        guard let data = try? JSONEncoder().encode(array) else { return "" }
        return String(data: data, encoding: .utf8)!
    }

}
极致的悲 2025-02-10 12:19:49

朋友请参考此答案将一系列对象保存到核心数据。它以很好的方式解释。我不知道您如何在核心数据中创建模型。但是,您应该在其所有属性的核心数据中创建和配方模型,并且使用使用该函数在您保存数据的同类中调用此功能。请讨论您是否有任何疑问或行不通。谢谢

func saveRecipeData(_ recipes: [Recipe]) {
let context = appDelegate.persistentContainer.viewContext
for recipe in recipes {
    let newRecipe = NSEntityDescription.insertNewObject(forEntityName: "Recipe", into: context)
    newRecipe.setValue(recipe.id, forKey: "id")
    // Save all the attributes in this way against its respective keys as I have done above.
}
do {
    try context.save()
    print("Success")
} catch {
    print("Error saving: \(error)")
}
}

Friend please refer to this answer Saving an array of objects to Core Data. It explains in well manner. I don't know how are you creating model in core data. But you should create and Recipe model in core data with all its attributes and the use call this function in the class where you are saving your data. Please feel to discuss if you have any question or it does not work. Thanks

func saveRecipeData(_ recipes: [Recipe]) {
let context = appDelegate.persistentContainer.viewContext
for recipe in recipes {
    let newRecipe = NSEntityDescription.insertNewObject(forEntityName: "Recipe", into: context)
    newRecipe.setValue(recipe.id, forKey: "id")
    // Save all the attributes in this way against its respective keys as I have done above.
}
do {
    try context.save()
    print("Success")
} catch {
    print("Error saving: \(error)")
}
}
农村范ル 2025-02-10 12:19:49

您可以将字符串数组存储在用键的用户默认式中,该键应该存储在Coredata实体中,但是您已经在结构中具有属性ID,因此我们可以在UserDefaults中存储成分和说明时使用它,因此可以使用属性创建实体:

选择手册/无

然后创建NSManagedCustomClass并将其添加到Bellow Project bellow任何类

在您的扩展中,添加两个数组:

import Foundation
import CoreData


extension CDRecipeStore {

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

    @NSManaged public var id: String?
    @NSManaged public var name: String?
    @NSManaged public var category: String?
    @NSManaged public var imageName: String?

}

extension CDRecipeStore : Identifiable {

//    return saved Ingredient and instructions Array 1, you can save ingrediant with id at any place in your code

    var ingredients: [String] {
        guard let id = self.id else {return []}
        let savedIngredients = UserDefaults.standard.array(forKey: "\(id + "ing")") as? [String]
        return savedIngredients ?? []
    }
    
    var instructions: [String] {
        guard let id = self.id else {return []}
        let savedInstructions = UserDefaults.standard.array(forKey: "\(id + "inst")") as? [String]
        return savedInstructions ?? []
    }
}

之后,当您从Web或Firebase获取数据时,您可以通过简单保存将其保存核心数据,还可以保存该对象的密钥ID的成分和指令,例如您的获取功能,您可以将此功能调用将将成分和指令保存到UserDefaults:

 func saveCoreData(reciepes:[Recipe]) {
    for reciepe in reciepes {
        let cdRecipe = CDRecipeStore(context: moc)
        cdRecipe.id = reciepe.id
        cdRecipe.category = reciepe.category
        cdRecipe.imageName = reciepe.imageName
        cdRecipe.name = reciepe.name
        UserDefaults.standard.set(reciepe.ingredients, forKey: "\(reciepe.id + "ing")")
        UserDefaults.standard.set(reciepe.instructions, forKey: "\(reciepe.id + "inst")")
        do {
            try? moc.save()
        }
    }
}

之后,您可以在检索其他字符串属性时从Coredata自定义类中检索数组

you can store array of strings in UserDefaults with key that should be store in coredata entity but already you have an property id in your struct so we can use it while storing ingredients and instructions in UserDefaults so create entity with properties :

enter image description here

after select manual/none
enter image description here

then create NSManagedCustomClass and add it bellow project bellow any class
enter image description here
in you extension add two arrays following:

import Foundation
import CoreData


extension CDRecipeStore {

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

    @NSManaged public var id: String?
    @NSManaged public var name: String?
    @NSManaged public var category: String?
    @NSManaged public var imageName: String?

}

extension CDRecipeStore : Identifiable {

//    return saved Ingredient and instructions Array 1, you can save ingrediant with id at any place in your code

    var ingredients: [String] {
        guard let id = self.id else {return []}
        let savedIngredients = UserDefaults.standard.array(forKey: "\(id + "ing")") as? [String]
        return savedIngredients ?? []
    }
    
    var instructions: [String] {
        guard let id = self.id else {return []}
        let savedInstructions = UserDefaults.standard.array(forKey: "\(id + "inst")") as? [String]
        return savedInstructions ?? []
    }
}

After that when you fetch data from web or firebase you can save it core data by simple save and also save the ingredients and instructions with key id of that object like your fetching function you can call this function it will save ingredients and instruction to UserDefaults:

 func saveCoreData(reciepes:[Recipe]) {
    for reciepe in reciepes {
        let cdRecipe = CDRecipeStore(context: moc)
        cdRecipe.id = reciepe.id
        cdRecipe.category = reciepe.category
        cdRecipe.imageName = reciepe.imageName
        cdRecipe.name = reciepe.name
        UserDefaults.standard.set(reciepe.ingredients, forKey: "\(reciepe.id + "ing")")
        UserDefaults.standard.set(reciepe.instructions, forKey: "\(reciepe.id + "inst")")
        do {
            try? moc.save()
        }
    }
}

after this you can easily retrieve array from coredata custom class as you retrieve other string properties

自找没趣 2025-02-10 12:19:49

我看到您分享了一些SwiftUI代码,而您是iOS的新手。核心数据是一个专家级别的框架,并且尚不完全了解SwiftUI。相反,我建议您走基于文档的路线,该路线确实在Swiftui内有一些本机支持。它可以与您现有的结构模型配合使用。它解释了视频在SwiftUI(WWDC 2021)中构建基于文档的应用程序。这是一个示例项目

I see you shared some SwiftUI code and you are new to iOS. Core Data is an expert level framework and integrating it with SwiftUI is not fully understood yet. Instead, I would recommend going the document-based route which does have some native support inside SwiftUI. It would work well with your existing struct model. It's explained the video Build Document Based Apps in SwiftUI (WWDC 2021). And here is a sample project Building a Document-Based App with SwiftUI (Sample Code).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文