Swift: create two objects each of them inside another - ios

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!

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)?

How to filter other parent of child with Vapor?

I have this request:
router.get("/fetchOngoingReleases") { (request) -> Future<[ReleaseOut]> in
return Release.query(on: request).filter(\.inprogress == true).all().map { releases in
var result: [ReleaseOut] = []
for r in releases {
var pageEvents: [Event] = []
let num = r.releaseUsers.query(on: request).filter(\.user.fbId ~~ "something").count()
var needAuthentication: Bool
if num == 0 {
needAuthentication = true
} else {
needAuthentication = false
}
let rOut = ReleaseOut(fbId: r.fbId, name: r.name, purpose: r.purpose, needAuthentication: needAuthentication)
result.append(rOut)
}
return result
}
}
}
It says I can not access (???) releaseUser.user.fbId in the query?
Here the data model:
and in code
final class Release: Content {
var id: Int?
var fbId: String
var inprogress: Bool?
var name: String
var purpose: String
/// Creates a new `Release`.
init(id: Int? = nil, fbId: String, name: String, purpose: String = "normal selling") {
self.id = id
self.fbId = fbId
self.name = name
self.purpose = purpose
}
}
extension Release {
var releaseUsers: Children<Release, ReleaseUser> {
return children(\.releaseId)
}
}
final class ReleaseUser: Content {
var id: Int?
var releaseId: Release.ID
var userId: User.ID
init(id: Int? = nil, releaseId: Release.ID, userId: User.ID) {
self.id = id
self.releaseId = releaseId
self.userId = userId
}
}
extension ReleaseUser {
var user: Parent<ReleaseUser, User> {
return parent(\.userId)
}
}
final class User: Content {
var id: Int?
var fbId: String
var name: String
init(id: Int? = nil, fbId: String, name: String) {
self.id = id
self.fbId = fbId
self.name = name
}
}
Ok so there are several things going on here, but the main concept is that you can't just jump across different tables like that - you need to use a JOIN to join the ReleaseUser table to the User table so you can then query on the fbId
Try changing your query to:
Release.query(on: request).filter(\.inprogress == true).join(\ReleaseUser.releaseId, to:\Release.Id).join(\ReleaseUser.userId, to:\User.Id).alsoDecode(User.self).all()
The alsoDecode will give you a tuple with the first position containing your original Release instance and the second containing the corresponding User instance. So, fbId should be available as:
r.1.fbId
In your case.

Swift Inheritance with custom array

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

How to modify instance value without using a function?

I have a class:
class WeaponItems {
var name: String
var index: Int
var price: Int
var weaponPower: Int = 0
var attackSpeed: Double = 0
var criticalChance: Double = 0
var criticalDamage: Double = 0
init(name: String, index: Int, price: Int){
self.name = name
self.index = index
self.price = price
}
var weaponBlade = WeaponItems(name: "Weapon Blade", index: 0, price: 300)
weaponBlade.weaponPower = 15
// Error: expected declaration
var swiftShooter = WeaponItems(name: "Swift Shooter", index: 1, price: 300)
swiftShooter.attackSpeed = 0.2
// Error: expected declaration
var minionsFoot = WeaponItems(name: "Minions Foot", index: 3, price: 300)
minionsFoot.criticalChance = 0.1
minionsFoot.criticalDamage = 0.1
// Error: expected declaration
}
I need to set weaponPower attackSpeed ... for each item, I got an error doing it this way.
I found answers saying you have to use a function to modify instances' values, but I feel that makes the code complicated, how do I set the value of it otherwise?
The concern of using a function is it'll separate the instance-creating and value-setting process, making the code harder to maintain.
you should add properties for all the weaponItems in the class
then your class implementation should look like this
class WeaponItems {
var name: String
var index: Int
var price: Int
var weaponPower: Int = 0
var attackSpeed: Double = 0
var criticalChance: Double = 0
var criticalDamage: Double = 0
var weaponBlade:WeaponItems{
get {
let tempWeaponBlade = WeaponItems(name: "Weapon Blade", index: 0, price: 300)
tempWeaponBlade.weaponPower = 15
return tempWeaponBlade
}
}
var swiftShooter:WeaponItems{
get {
let tempSwiftShooter = WeaponItems(name: "Swift Shooter", index: 1, price: 300)
tempSwiftShooter.attackSpeed = 0.2
return tempSwiftShooter
}
}
var minionsFoot:WeaponItems{
get {
let tempMinionsFoot = WeaponItems(name: "Minions Foot", index: 3, price: 300)
tempMinionsFoot.criticalChance = 0.1
tempMinionsFoot.criticalDamage = 0.1
return tempMinionsFoot
}
}
init(name: String, index: Int, price: Int){
self.name = name
self.index = index
self.price = price
}
}
If you wish to have default property values, which you would also like the opportunity to customise when creating an instance, then I would recommend using default parameter values in your initialiser. This will allow you to create a new instance of your WeaponItems class with the actual property values known at initialisation, rather than some default values which you then change immediately after.
I also strongly agree with Luca D'Alberti – there is no need for your 'preset weapons' to be instance properties. As they don't rely on any instance state, or are unique to a given instance – they should be static.
For example:
class Weapon {
static var blade : Weapon {
return Weapon(name: "Blade", index: 0, price: 300, power: 15)
}
static var swiftShooter : Weapon {
return Weapon(name: "Swift Shooter", index: 1, price: 300, attackSpeed: 0.2)
}
static var minionsFoot : Weapon {
return Weapon(name: "Minions Foot", index: 3, price: 300, criticalChance: 0.1, criticalDamage: 0.1)
}
var name: String
var index: Int
var price: Int
var power: Int
var attackSpeed: Double
var criticalChance: Double
var criticalDamage: Double
init(name: String, index: Int, price: Int,
power: Int = 0, attackSpeed: Double = 0,
criticalChance: Double = 0, criticalDamage: Double = 0) {
self.name = name
self.index = index
self.price = price
self.power = power
self.attackSpeed = attackSpeed
self.criticalChance = criticalChance
self.criticalDamage = criticalDamage
}
}
let blade = Weapon.blade
let swiftShooter : Weapon = .swiftShooter
In your case, if the code would compile, to use your pre-created weaponBlade, you have to create two WeaponItems instances as below:
let balde = WeaponItems(name: "", index: 0, price: 0).weaponBlade
That's not the best solution, even because in your case doesn't compile at all (you can read the comment by #gnasher729 to understand why).
What I suggest you is to create static instances of them
extension WeaponItems {
static var Blade: WeaponItems {
get {
let blade = WeaponItems(name: "The name", index: 1, price: 300)
blade.weaponPower = 15
return blade
}
}
}
And you can now use the blade by typing WeaponItems.Blade, or if it the type is easily inferred as below:
let blade: WeaponItems = .Blade
You can try using like below code.
lazy var weaponBlade:WeaponItems = {
let _weaponBlade = WeaponItems(name: "Weapon Blade", index: 0, price: 300)
_weaponBlade.weaponPower = 15
return _weaponBlade
}()
Please refer this link to know more about lazy variable.

Realm object changed, another copy of that object has changed too, why?

I am stuck in a problem. Let's assume I have this Realm Model:
class Table: Object {
dynamic var id = 0
dynamic var x: Int = 0
dynamic var y: Int = 0
dynamic var width:Int = 0
dynamic var height: Int = 0
dynamic var text: String = ""
dynamic var color: String = ""
dynamic var type: String = ""
let food = List<Food>()
override static func primaryKey() -> String {
return "id"
}
}
class Food : Object {
dynamic var id: Int = 0
dynamic var name = ""
dynamic var ingredients: String = "" // bigger text field
dynamic var size: Int = 0 // none, small, medium, big size
dynamic var price: Float = 0.0
dynamic var category: Category?
let additionalIngredients = List<Ingredient>()
override static func primaryKey() -> String {
return "id"
}
}
Let's say I have one table and added 2 times the same food on that table like so :
try! realm.write(){
table.food.append(food) // A
table.food.append(food) // B
realm.add(table, update: true)
}
If I change the additionalIngredients for food A , also at the same food B changes its values. I am doing that changes with this transaction :
try! realm.write(){
table.food.first!.additionalIngredients.removeAll()
for ingredient in ingredientsToAdd{
table.food.first!.additionalIngredients.append(ingredient)
}
realm.add(table, update: true)
}
I guess I am doing something wrong regarding the reference/instance, can someone give me a hint?
Thanks in advance!
List.append() adds the object itself to the list and not a copy of the object, so you only have one Food object.

Resources