У меня очень похожий вопрос к Сохранение массива пользовательских объектов, каждый из которых содержит массив пользовательских объектов, лучший метод? , за исключением того, что я в настоящее время пытаюсь использовать Realm для хранения мои данные вместо CoreData. Я хотел бы знать:
- если есть веская причина, я должен рассмотреть переделку своего кода для реализации CoreData вместо Realm
- , если 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
}
}