Swift Inheritance with custom array - ios

class RecipeBrain: NSObject {
var name: String
var pictureUrl: String
var likes = 0
var ingredients: [Ingredient]
var method: [String]
init(name: String, pictureUrl: String, ingredients: [Ingredient], method: [String]) {
self.name = name
self.pictureUrl = pictureUrl
self.ingredients = ingredients
self.method = method
}
}
class Ingredient{
var name: String
var quantity: Double
var unit: String
init(name: String, quantity: Double, unit: String) {
self.name = name
self.quantity = quantity
self.unit = unit
}
}
class AddRecipe {
var recipeBrain = [RecipeBrain]()
var ingredients = [Ingredient]()
var ingredient = Ingredient(name: "apple", quantity: 1.0, unit: "Kg")
ingredients.append(ingredient)
var recipe1 = RecipeBrain(name: "Recipe1", pictureUrl: "nil", ingrexdients: ingredients, method: ["Method"])
recipeBrain.append(recipe1)
}
I am trying to build a recipe app in Swift. Problem is creating the ingredients for it where I require a string,double,string.
How I imagined : an ingredient is an array of Ingredients. and to create a new recipe I just .append it to the recipeBrain
Main problem : when I try to append a new recipe to the recipeBrain array It says that the recipe1 is not declared.
( The AddRecipe class purpose is only testing with static data )
I changed it to recipeBrain.append(recipe1) But I still get the error : expected declaration , same with ingredients when I try to append

You are trying to append recipe and ingredient objects into their arrays in body of AddRecipe class, but you can't.
if you do this in body of a method everything will be ok, for example in init() method:
class AddRecipe {
var recipeBrain = [RecipeBrain]()
var ingredients = [Ingredient]()
init()
{
var ingredient = Ingredient(name: "apple", quantity: 1.0, unit: "Kg")
ingredients.append(ingredient)
var recipe1 = RecipeBrain(name: "Recipe1", pictureUrl: "nil", ingredients: ingredients, method: ["Method"])
recipeBrain.append(recipe1)
}

You are getting the error message because you have tried to write code in a class declaration. You can only declare items such as properties, functions, enumerations and other classes directly inside a class declaration. Code, such as ingredients.append(ingredient) needs to go inside a function.
I would suggest that you move this code into a class function of your RecipeBrain class (or indeed put it somewhere else entirely, such as a view controller, but you haven't shown how your app is structured):
class RecipeBrain: NSObject {
var name: String
var pictureUrl: String
var likes = 0
var ingredients: [Ingredient]
var method: [String]
init(name: String, pictureUrl: String, ingredients: [Ingredient], method: [String]) {
self.name = name
self.pictureUrl = pictureUrl
self.ingredients = ingredients
self.method = method
}
class func addRecipe() -> [RecipeBrain] {
var recipeBrain = [RecipeBrain]()
var ingredients = [Ingredient]()
let ingredient = Ingredient(name: "apple", quantity: 1.0, unit: "Kg")
ingredients.append(ingredient)
let recipe1 = RecipeBrain(name: "Recipe1", pictureUrl: "nil", ingredients: ingredients, method: ["Method"])
recipeBrain.append(recipe1)
return recipeBrain
}
}
Now you can say let recipeBrain = RecipeBrain.addRecipe() and recipeBrain will be an array of RecipeBrain containing a single RecipeBrain

Related

Primary key in realm database

I create a default realm file to use it during first launching app as replacement (I want to have a file with initial data). I start with creating default realm file from csv files. The problem is that I am not sure if my structure is correct. When I import data from csv (in Realm Browser) and try to import next data for next class, I get this error
I have main class called Exercises
class Exercises: Object {
#Persisted var id: Int = 0
#Persisted var name: String = ""
#Persisted var category: Category?
#Persisted var equipment: Equipment?
#Persisted var instruction: String
#Persisted var muscle: List<Muscle>
#Persisted var gif: String?
#Persisted var image: String?
convenience init(id: Int, name: String, category: Category?, equipment: Equipment?, instruction: String, muscle: [Muscle], gif: String?, image: String?) {
self.init()
self.id = id
self.name = name
self.category = category
self.equipment = equipment
self.instruction = instruction
self.muscle.append(objectsIn: muscle)
self.gif = gif
self.image = image
}
}
and other classes for separate things
class Equipment: Object {
#Persisted(primaryKey: true) var equipmentID = 0
#Persisted var equipment: String = ""
convenience init(equipment: String) {
self.init()
self.equipment = equipment
}
}
class Category: Object {
#Persisted(primaryKey: true) var categoryID = 0
#Persisted var category: String = ""
convenience init(category: String) {
self.init()
self.category = category
}
}
class Muscle: Object {
#Persisted(primaryKey: true) var muscleID = 0
#Persisted var muscle: String = ""
convenience init(muscle: String) {
self.init()
self.muscle = muscle
}
}
Finally I want to receive structure like below. I wonder if it is correct way? Maybe better option is just set text in fields instead of reference to class (after all realm is non-relational)?

Swift Realm - Iterate an array of items to update their relationships

I have a basic many-to-many relation with a relation table on my Realm Schema.
So I have Recipe, Ingredient and RecipeIngredient model.
When I try to create a Recipe, I have to iterate an array of Ingredient to create RecipeIngredient. Once the recipeIngredient is create I want to edit my Recipe and my Ingredient to add a relation to the new RecipeIngredient. But the edition of the Ingredient throws an exception, and I have no idea why...
Here some code
Recipe Model
class RecipeRealm: Object, ObjectKeyIdentifiable {
#Persisted(primaryKey: true) var _id: ObjectId
#Persisted var name: String = ""
#Persisted var lastEditedTime: Date = Date()
#Persisted var recipeIngredients: List<RecipeIngredient>
convenience init(name: String){
self.init()
self.name = name
}
}
Ingredient Model
class IngredientRealm: Object, ObjectKeyIdentifiable {
#Persisted(primaryKey: true) var _id: ObjectId
#Persisted var name: String = ""
#Persisted var unit: Unit = Unit.none
#Persisted var lastEditedTime: Date = Date()
#Persisted var recipeIngredients: List<RecipeIngredient>
convenience init(name: String){
self.init()
self.name = name
}
}
RecipeIngredient Model
class RecipeIngredient: Object, ObjectKeyIdentifiable {
#Persisted(primaryKey: true) var _id: ObjectId
#Persisted var qty: Int = 0
#Persisted var lasEditedTime: Date = Date()
#Persisted(originProperty: "recipeIngredients") var recipe: LinkingObjects<RecipeRealm>
#Persisted(originProperty: "recipeIngredients") var ingredient: LinkingObjects<IngredientRealm>
}
The recipe form model
struct QuantifiedIngredient {
var ingredient: IngredientRealm
var qty: Int16
}
class RecipeForm: ObservableObject {
#Published var name = ""
#Published var ingredients: [QuantifiedIngredient] = []
var recipeID: String?
var updating: Bool {
recipeID != nil
}
init(){}
init(_ recipe: Recipe){
name = recipe.name ?? ""
ingredients = []
recipeID = recipe.id
}
}
The create Recipe logic
private func createRecipe() {
withAnimation {
do {
let realm = try Realm()
// Create Recipe on RealmDB
let realmRecipe = RecipeRealm(name: form.name)
try realm.write{
realm.add(realmRecipe)
for ingredient in form.ingredients{
let recipeIngredient = RecipeIngredient()
recipeIngredient.qty = Int(ingredient.qty)
realm.add(recipeIngredient)
realmRecipe.recipeIngredients.append(recipeIngredient)
ingredient.ingredient.recipeIngredients.append(recipeIngredient) // <--- this line crash
}
}
} catch {
print(error.localizedDescription)
}
presentationMode.wrappedValue.dismiss()
}
}
An exception is throw by this line on createRecipe method: ingredient.ingredient.recipeIngredients.append(recipeIngredient).
Here the error message: Terminating app due to uncaught exception 'RLMException', reason: 'Cannot modify managed RLMArray outside of a write transaction.'
But I have the write block...
Any ideas ?
It seems that when I tried to add recipeIngredient on the ingredient, I actually tried to put a realm object on a copy of the realm ingredient. So is obviously not working, but the error message is not very clear.
To fix it I used the thaw()function that returns me the good realm object, so I can edit it.
try realm.write{
realm.add(realmRecipe)
for ingredient in form.ingredients{
let recipeIngredient = RecipeIngredient()
recipeIngredient.qty = Int(ingredient.qty)
realm.add(recipeIngredient)
realmRecipe.recipeIngredients.append(recipeIngredient)
guard let rIngredient = ingredient.ingredient.thaw() else {
return
}
rIngredient.recipeIngredients.append(recipeIngredient)
}
}
I don't know if this is the best way to do it, so if someone had a better option I'm listening :)

Swift: create two objects each of them inside another

I developed an iOS app which have two objects, each of one inside another, as below:
first one:
class OfferItem
{
var _id : Int? = 0
var _OfferId : Int? = 0
var _ItemId : Int? = 0
var _Discount : Int? = 0
var _item = Item()
..
functions()
}
and 2nd one:
class Item
{
var _id : Int! = 0
var _RateCount : Int? = 0
var _Offer = OfferItem()
..
functions()
}
How to resolve that in such away where I can call each object in another?
You must read about references in Swift. Automatic Reference Counting link
Here is your example:
class OfferItem {
var id: Int?
var discount: Int?
var item: Item!
init(id: Int? = nil, discount: Int? = nil, itemId: Int, itemRateCount: Int) {
self.id = id
self.discount = discount
self.item = Item(id: itemId, rateCount: itemRateCount, offer: self)
}
}
class Item {
var id = 0
var rateCount = 0
unowned var offer: OfferItem
init(id: Int, rateCount: Int, offer: OfferItem) {
self.id = id
self.rateCount = rateCount
self.offer = offer
}
}
var offerItem = OfferItem(id: 10, discount: 2, itemId: 1, itemRateCount: 20)
print(offerItem.item.id, offerItem.item.offer.id)
Result: 1 Optional(10)
I hope to help you with my answer above!

How to construct a json object from list of class objects

I'm looking on how to construct or create a son object from a list of class objects.
I have a Category class which look like :
class Category {
var Code: Int?
var Label: String?
init(Code: Int, Label: String) {
self.Code = Code
self.Label = Int
}
}
and then I have a list of category var categories = [Category]()
and then I append my list like this :
categories.append(5,"Shoes")
How can I construct a json object which will look like this :
{
"List":[
{
"Code":"5",
"Label":"Shoes"
},
....
]
}
Step 1
First of all we update your Category class.
class Category {
var code: Int // this is no longer optional
var label: String // this neither
init(code: Int, label: String) {
self.code = code
self.label = label
}
var asDictionary : [String:AnyObject] {
return ["Code": code, "Label": label]
}
}
Step 2
Now we create a list of categories
var categories = [
Category(code: 0, label: "zero"),
Category(code: 1, label: "one"),
Category(code: 2, label: "two")
]
Then we transform them into a list of dictionaries
let list = categories.map { $0.asDictionary }
And finally let's create the json
let json = ["List":list]
That looks valid
NSJSONSerialization.isValidJSONObject(json) // true
Hope this helps.

Why can I put a struct into an array on a playground but not in a view controller

Why does this work fine on a playground but when I put it into a viewController it returns a "viewController.type does not have a member named extent"
It's driving me mad so I'd really appreciate any help!!!
class ViewController: UIViewController {
struct TopicBook {
var name: String
var species: [String]
var subject: String
var rotation: [String]
var unit: String
var extra: String
var content: String
var level: [(Int,Int)]
init(name: String, species: [String], subject: String, rotation: [String], unit: String, extra: String, content: String, level: [(Int,Int)]) {
self.name = name
self.species = species
self.subject = subject
self.rotation = rotation
self.unit = unit
self.extra = extra
self.content = content
self.level = level
}
}
var extext = TopicBook (name: "Name" , species: ["species","species"], subject: "subject", rotation: ["rotation"], unit: "unit", extra: "extra", content: "content", level: [(1,1)])
let sete = [extent]
Try this
struct TopicBook {
var name: String
var species: [String]
var subject: String
var rotation: [String]
var unit: String
var extra: String
var content: String
var level: [(Int,Int)]
init(name: String, species: [String], subject: String, rotation: [String], unit: String, extra: String, content: String, level: [(Int,Int)]) {
self.name = name
self.species = species
self.subject = subject
self.rotation = rotation
self.unit = unit
self.extra = extra
self.content = content
self.level = level
}
}
class ViewController: UIViewController {
var extent:TopicBook?
var extent2:TopicBook?
override func viewDidLoad() {
super.viewDidLoad()
extent = TopicBook (name: "Name" , species: ["species","species"], subject: "subject", rotation: ["rotation"], unit: "unit", extra: "extra", content: "content", level: [(1,1)])
extent2 = TopicBook (name: "JustToShow" , species: ["JustToShow","JustToShow"], subject: "JustToShow", rotation: ["JustToShow"], unit: "JustToShow", extra: "JustToShow", content: "JustToShow", level: [(2,2)])
}
override func viewDidAppear(animated:Bool){
super.viewDidAppear(true)
//If you want it to have multiple TopicBooks inside, do this
//var seteMutable:[TopicBook] = [ ]
//seteMutable =[extent!]
//seteMutable.append(extent2!)
//let seteTrial = seteMutable
//println(seteTrial[0].name)
//println(seteTrial[1].name)
//else if you want it to have just one TopicBook inside, do this
let sete = [extent!]
// sete is a TopicBook array now
//you can use sete[0]
//Placing it inside viewDidAppear is an example, you can define "sete" in anywhere you will use it.
//viewDidAppear gets called after viewDidLoad, this is why i put it here
}
}

Resources