【问题标题】:Save Array of Strings to CoreData将字符串数组保存到 CoreData
【发布时间】:2020-01-02 08:32:51
【问题描述】:

我正在尝试将 6 个字符串的数组保存到 CoreData,如下所示:

     let imageUrls = ["image-url....", "image-url....", ..., "image-url"]

我已尝试How to save Array to CoreData? 和Best practice? - Array/Dictionary as a Core Data Entity Attribute 中所述的所有方法,但均未成功。

这是我正在尝试做的方法。

在我的 .xcdatamodeld 中,我声明: imageUrl 作为一个可变形的,见链接中的图片(无法将其附加到帖子中,对此我很抱歉!):https://drive.google.com/file/d/1VJey55oD9KhOy1KDy59h8PweMMQnaK2-/view?usp=sharing

在我的 NSManagedObject 类中

    @objc(Entity)
    public class Entity: NSManagedObject {
    @NSManaged public var imageUrls: [String]?
    ....

这是我在将实体保存到 CoreData 之前创建实体的方式:

    entity.imageUrls = ["test", "test", "test"]

当我尝试获取 imageUrls 时,获取的 entity.imageUrls 等于 nil。我不明白这一点。预期的结果与我保存到 CoreData 的数组相同。

乔金·丹尼尔森回答

【问题讨论】:

  • 您是否在模型中将自定义类设置为 [String] 以获取属性?
  • 是的,忘记说了!
  • 也许你需要清理和重建你的项目。我刚刚创建了一个简单的测试项目,它使用 Transformable 和设置自定义类工作正常
  • 我忘记了我必须清除所有 nil 对象的 CoreData ......它起作用了。非常感谢!
  • 嘿,@CoderOgden 我遇到了这个确切的问题。我尝试清理构建文件夹并重新构建,但结果仍然相同。您能否进一步解释一下您是如何解决此问题的?

标签: arrays swift core-data


【解决方案1】:

我的建议是将数组编码/解码为 JSON 并使用计算属性。从 Swift 的角度来看,这可能比 transformable 属性更有效,后者将数组桥接到 Objective-C 运行时并使用更重的 NSCoding。

@NSManaged public var imageUrls: String

var urls : [String] {
    get {
        let data = Data(imageUrls.utf8)
        return (try? JSONDecoder().decode([String].self, from: data)) ?? []
    }
    set {
        guard let data = try? JSONEncoder().encode(newValue),
            let string = String(data: data, encoding: .utf8) else { imageUrls = "" }
        imageUrls = string
    }
}

另一个好处是可以搜索 JSON 字符串

【讨论】:

  • 可搜索性是个好点。感谢您的观点。
【解决方案2】:

检查下面的附件以了解“.xcdatamodelId”文件中的声明。之后在 CoreDataProperties.swift 文件中声明以下行

@NSManaged public var thumbnail: [String]?

现在,我们可以将字符串数组初始化为缩略图变量。

【讨论】:

  • 为什么是 Array 而不是 Array?
  • 我们可以使用 Array 。它也可以。我只使用 Array 所以我不需要每次都更新模型。
  • 就我而言,我必须使用非可选类型
  • 另外,将NSSecureUnarchiveFromData 设置为Value Transformer(它被重命名为“Transformer”)。否则,您可能会收到此运行时警告:'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
【解决方案3】:

将 imageUrl 的类型更改为 BinaryData,然后将您的列表转换为数据并保存。

let urls = NSKeyedArchiver.archivedData(withRootObject: imageUrls)
manageObject.setValue(urls, forKey: "imageUrls")

【讨论】:

    【解决方案4】:

    斯威夫特 5

    我发现vadian 的回答很有帮助。我使用了相同的想法,但以不同的方式。提供我的代码,希望对您有所帮助。

    • 选择要将数组存储为字符串的属性的类型

    //保存到核心数据

    var quizManagedObject : [NSManagedObject] = []
    
    func save(question: String, answers: [String]) {
    
        guard let data = try? JSONEncoder().encode(answers),
        let answersEncodedString = String(data: data, encoding: .utf8) else { return }
    
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
    
        let entity = NSEntityDescription.entity(forEntityName: "Quiz", in: managedContext)!
        let quiz = NSManagedObject(entity: entity, insertInto: managedContext)
    
        quiz.setValue(question, forKeyPath: "question")
        quiz.setValue(answersEncodedString, forKeyPath: "answers")
    
        do {
            quizManagedObject.append(quiz)
            try managedContext.save()
        } catch let error as NSError {
            print("Could not save. \(error), \(error.userInfo)")
        }
    }
    

    // 从核心数据中获取

    func fetchCoreData() {
    
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Quiz")
    
        do {
            quizManagedObject = try managedContext.fetch(fetchRequest)
    
            for i in quizManagedObject {
                if let decodedAnswerString = i.value(forKey: "answers") as? String {
                    let data = Data(decodedAnswerString.utf8)
                    let answerArray = try? JSONDecoder().decode([String].self, from: data)
                    let question = i.value(forKey: "question") as! String
    
                    print("Q : ", question)
                    print("A : ", answerArray ?? [""])
                }
            }
        } catch let error as NSError {
            print("Could not fetch. \(error), \(error.userInfo)")
        }
    }
    

    【讨论】:

      【解决方案5】:

      您必须将其作为字符串保存到核心数据中,并使用分隔符拆分数组。问题是您必须确保字符串不会包含该分隔符。

      例如,如果您在将数组保存到核心数据时使用分隔符“,”,则必须像

      一样保存它
      coreData.arrayToStringValue = array.joined(separator: ", ")
      

      当您读取数据时,您必须像这样读取它:

      let arrayFromStringValue:[String] = coreDataValue.split(separator: ", ")
      

      【讨论】:

      • 您好,感谢您的回答!这是一个好主意,但它是一种解决方法。我可能会选择这个解决方案,但我很感兴趣为什么我的也不起作用......
      【解决方案6】:

      如果您的对象可以在没有任何自定义类的情况下进行转换,您可能希望将其转换为 [NSObject] 并像这样保存它,因为它是 Transformable 基类型。但您可能应该将 [String] 作为基类。

      也没有迹象表明您曾经将数据保存到core data?您所显示的只是在模型中分配一个变量。你真的不应该这样做,因为他们应该是immutable而不是mutable。

      【讨论】:

        【解决方案7】:

        以下是我们可以存储的数据类型。

        您不能存储数组数据。您需要转换为逗号分隔的字符串。然后尝试将其保存到 coredata 中。并且在获取时,您可以将其转换为array。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-12-08
          • 2023-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-19
          • 2015-07-01
          相关资源
          最近更新 更多