Как сохранить пользовательский типизированный объект, который содержит массив пользовательских структур, в область (в swift)? - PullRequest
1 голос
/ 08 февраля 2020

У меня очень похожий вопрос к Сохранение массива пользовательских объектов, каждый из которых содержит массив пользовательских объектов, лучший метод? , за исключением того, что я в настоящее время пытаюсь использовать Realm для хранения мои данные вместо CoreData. Я хотел бы знать:

  1. если есть веская причина, я должен рассмотреть переделку своего кода для реализации CoreData вместо Realm
  2. , если Realm все еще хороший вариант, как мне это сделать? правильно реализовать мой массив IngredientObjects, который представляет собой массив пользовательских структур внутри моего RecipeObjet.

Код создается, но когда я добавляю новый Recipe в свое приложение и нажимаю сохранить, он вылетает с ошибкой

"Terminating app due to uncaught exception 'RLMException', 
reason: 'Property 'ingredients' is declared as 'NSArray', which is not a supported RLMObject property type"

Первоначально я создаю класс Recipe, который содержит массив Ingredient структур. Однажды я решил go с Realm, создал класс RecipeObject и класс IngredientObject, которые должны быть форматами данных, удобными для хранения. Я также создал протокол Persistable и сделал класс Recipe и расширение структуры Ingrededient Persistable, чтобы иметь методы для существенного преобразования Recipe в RecipeObject и Ингредиент в IngredientObject.

Наконец, мой первый метод хранения - это метод add в моем классе RecipeStore; Я еще не реализовал никаких методов извлечения.

Код ниже:

//Recipe.swift
import UIKit
import os.log
import Foundation
import RealmSwift

public class Recipe: Persistable {

    //MARK: Properties
    dynamic var name: String
    dynamic var numServed: Float?
    dynamic var photo: UIImage?
    dynamic var rating: Int
    dynamic var ingredients: [Ingredient]
    var notes: String?


    //MARK: Initialization

    init?(name: String, numServed: Float?, ingredients: [Ingredient], photo: UIImage?, rating: Int, notes: String?) {

        // The name must not be empty
        guard !name.isEmpty else {
            return nil
        }

        // The rating must be between 0 and 5 inclusively
        guard (rating >= 0) && (rating <= 5) else {
            return nil
        }

        // Initialize stored properties.
        self.name = name
        self.numServed = numServed
        self.photo = photo
        self.rating = rating
        self.ingredients = ingredients
        self.notes = notes
    }

    //Persistable required functions
    //Create a Recipe from a RecipeObj
    required public init(managedObject: RecipeObject) {
        name = managedObject.name ?? ""
        numServed = managedObject.numServed ?? 0.0
        photo = UIImage(data: managedObject.photo as! Data) ?? nil
        rating = managedObject.rating ?? 0
        ingredients = [Ingredient]()
        //ingredients = managedObject.ingredients.flatMap(Ingredient.init(managedObject:))
        let count = managedObject.ingredients?.count ?? 0
        if (count > 0) {
            for i in 0...count {
                ingredients[i].qty = managedObject.ingredients?[i].qty
                ingredients[i].uom = managedObject.ingredients?[i].uom
                ingredients[i].name = managedObject.ingredients?[i].name
            }
        }
        notes = managedObject.notes ?? ""
    }

    //Create a RecipeObject from a Recipe
    public func managedObject() -> RecipeObject {
        let objName = name ?? ""
        let objNumServed: Float = numServed ?? 0.0
        let objPhoto = photo
        let objRating = rating ?? 0
        var objIngredients = [IngredientObject]()
        for i in 0...ingredients.count {
            objIngredients[i] = ingredients[i].managedObject()
        }
        let objNotes = notes ?? ""
        let recipeObject = RecipeObject(name: objName, numServed: objNumServed, photo: objPhoto!, rating: objRating, ingredients: objIngredients, notes: objNotes ?? "")
        return recipeObject
    }
}

____________________
//Ingredient.swift
import Foundation

public struct Ingredient {
    //Properties
    public var qty: Float?
    public var uom: String?
    public var name: String?
}

_______________________
//RecipeObject.swift
import Foundation
import RealmSwift

final public class RecipeObject: Object {
    @objc dynamic var name = UUID().uuidString
    @objc dynamic var numServed: Float = 0.0
    @objc dynamic var photo: NSData? = nil
    @objc dynamic var rating: Int = 0
    @objc dynamic var ingredients: [IngredientObject]? = nil
    @objc dynamic var notes: String? = ""
    //dynamic var recipeID = UUID().uuidString


    convenience init(name: String, numServed: Float, photo: UIImage, rating: Int, ingredients: [IngredientObject]?, notes: String) {
        //debug
        print ("REcipeObject required init")
        self.init()
        self.name = name
        self.numServed = numServed
        if let data = photo.pngData() {
            self.photo = data as NSData
        } else if let data = photo.jpegData(compressionQuality: 0.0) {
            self.photo = data as NSData
         } else {
            self.photo = nil
        }

        self.rating = rating
        self.ingredients = ingredients
        self.notes = notes
    }

    override public static func primaryKey() -> String? {
        return "name"
    }
}


_____________________
//IngredientObject.swift
import Foundation
import RealmSwift

final public class IngredientObject: Object {
    @objc dynamic var qty: Float = 0.0
    @objc dynamic var uom = ""
    @objc dynamic var name = ""
    //@objc dynamic var ingredientID = UUID().uuidString

   override public static func primaryKey() -> String? {
        return "name"
    }
}

_______________________
//IngredientPersistable.swift
import Foundation
import RealmSwift

extension Ingredient: Persistable {

    //assign struct values FROM an IngredientObject
    public init(managedObject: IngredientObject) {
        qty = managedObject.qty
        uom = managedObject.uom
        name = managedObject.name
    }

    //assign struct values TO an ingredient object
    public func managedObject() -> IngredientObject {
        let ingredient = IngredientObject()
        ingredient.qty = qty ?? 0.0
        ingredient.uom = uom ?? ""
        ingredient.name = name ?? ""
        return ingredient
    }
}

_______________
//Persistable.swift

import Foundation
import RealmSwift

/// Represents a type that can be persisted using Realm.
public protocol Persistable {

    associatedtype ManagedObject: Object
    //associatedtype PropertyValue: PropertyValueType = DefaultPropertyValue
    //associatedtype Query: QueryType = DefaultQuery

    init(managedObject: ManagedObject)

    func managedObject() -> ManagedObject
}

_________________
//RecipeStore.swift

import UIKit
import Foundation
import RealmSwift

enum RuntimeError: Error {
    case NoRealmSet
}
class RecipeStore {
var realm: Realm?

    public func addRecipe(_ recipe: Recipe) throws
    {
        if (realm != nil) {
            var newRecipeObject: RecipeObject
            newRecipeObject = recipe.managedObject()
            try! realm?.write {
                realm?.add(newRecipeObject)
            }
        } else {
            throw RuntimeError.NoRealmSet
        }
    }
...