Environmentobject keep track of arrays variables - swift

I'm pretty new to xCode so this could have an obvious answer.
I've just learned about environment objects and created the following one:
import SwiftUI
class Data: ObservableObject {
#Published var types = [Type]()
#Published var customers = [Customer]()
#Published var templates = [SubscriptionTemplate]()
#Published var subscriptions = [Subscription]()
#Published var giftCodes = [Giftcode]()
}
As you can see the object contains an array of objects. One of these is a customer array. The customer object looks like this:
import SwiftUI
class Customer: Identifiable, Codable{
var id: Int
var firstname: String
var lastname: String
var address: String
var plz: Int
var place: String
var credit: Int
init(id: Int, firstname: String, lastname: String, address: String, plz: Int, place: String, credit: Int) {
self.id = id
self.firstname = firstname
self.lastname = lastname
self.address = address
self.plz = plz
self.place = place
self.credit = credit
}
}
extension Customer: Equatable {
static func == (lhs: Customer, rhs: Customer) -> Bool {
return lhs.id == rhs.id
}
}
In my project, I implemented an API call to update the customer. This works like a charm, but after updating, I also want to fetch the customer objects with the following method:
API().fetchCustomers { (customers) in
self.data.customers = customers
}
After updating an object this doesn't work. The environment object doesn't update, but after creating a new object or fetching the data initial, it works.
What is the difference between the update and the create / fetch?

Make Customer a value type (ie. struct):
struct Customer: Identifiable, Codable{
var id: Int
// ... other code

Related

Overlapping accesses to 'but modification requires exclusive access; consider copying to a local variable'

an employee can own more than one animal, but an animal must have only one employee.
First, I add an employee. Then when adding an animal, I select the employee.
After selecting the employee, I press the save button.
I want to transfer the animal I just added to that employee.
I want to take the employee's id and add it to the employee attribute of the animal I added.
Animal Model:
struct Animal {
let id: String?
var name: String?
var sound: String?
var age: Double?
var waterConsumption: Double?
var employee: Employee?
var animalType: String?
}
Employee Model:
struct Employee {
let id: String?
var name: String?
var lastName: String?
var age: Int?
var gender: String?
var salary: Double?
var experienceYear: String?
var animals: [Animal]?
}
ZooManager:
Error is on this line: newAnimal.employee?.animals?.append(newAnimal)
Overlapping accesses to 'newAnimal.employee', but modification requires exclusive access; consider copying to a local variable
protocol ZooManagerProtocol {
var animals: [Animal] { get set }
var employees: [Employee] { get set }
func addNewAnimal(_ model: Animal)
}
class ZooManager: ZooManagerProtocol {
static var shared = ZooManager()
var animals: [Animal] = []
var employees: [Employee] = []
private init() { }
func addNewAnimal(_ model: Animal) {
var newAnimal = model
guard var employee = employees.filter({ $0.id == model.employee?.id }).first else { return }
newAnimal.employee = employee
newAnimal.employee?.animals?.append(newAnimal)
dump(newAnimal)
}
func addNewEmployee(_ model: Employee) {
employees.append(model)
}
}
The solution recommended by the compiler works
func addNewAnimal(_ model: Animal) {
var newAnimal = model
guard var employee = employees.filter({ $0.id == model.employee?.id }).first else { return }
employee.animals?.append(newAnimal)
newAnimal.employee = employee
}
I've never seen this error before, hopefully someone can add a good answer explaining the why and not just the how!
EDIT:
Here's the why https://github.com/apple/swift-evolution/blob/main/proposals/0176-enforce-exclusive-access-to-memory.md

Inheritance from non-protocol type 'PFObject'

I am getting this error Inheritance from non-protocol type 'PFObject' on Xcode with Swift while trying to create a Model, here is the code of the model:
import Foundation
import ParseSwift
import Parse
import SwiftUI
struct Category: ParseObject, PFObject {
// Required properties from ParseObject protocol
var originalData: Data?
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
// Custom fields for the contact's information
var name: String = ""
var cover: String = ""
var color: String = ""
var createdBy: String = ""
}
extension Category {
init(name: String, cover: String, color: String, createdBy: String) {
self.name = name
self.cover = cover
self.color = color
self.createdBy = createdBy
}
}
What am I doing wrong?
It looks like you are trying to use Parse-Swift and the Parse Objective-C SDK at the same time which you shouldn't be doing. Your ParseObject is setup using Parse-Swift so assuming that's what you want to use, remove, import Parse and your Parse Object should look like:
import Foundation
import ParseSwift
import SwiftUI
struct Category: ParseObject {
// Required properties from ParseObject protocol
var originalData: Data?
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
// All Custom fields should be optional
var name: String?
var cover: String?
var color: String?
var createdBy: String?
}
extension Category {
init(name: String, cover: String, color: String, createdBy: String) {
self.name = name
self.cover = cover
self.color = color
self.createdBy = createdBy
}
}
Remove the Parse dependency completely from your project as Parse-Swift doesn't use or need it at all. The playgrounds in Parse-Swift show how to use the SDK correctly along with any imports that are needed to use the SDK.

Create an object array with few object properties of another object array using map

Suppose we have an Employee class like this
class Employee {
var id: String?
var name: String?
var role: String?
var age: Int?
var salary: Int?
}
var employeeList: [Employee]
I have to create a new object array with just few properties(eg: id, name, age) from employeeList.
Is there any other way(like map) other than using a for-loop to iterate the employeeList?
If you wanted to use map, you could do something like the following:
class Employee {
var id: String?
var name: String?
var role: String?
var age: Int?
var salary: Int?
}
var employeeList: [Employee]
var employeeModifiedList = employeeList.map {
(id: $0.id, name: $0.name, age: $0.age)
}
Something like this?
let myData: [(String?, String?, Int?)] = employeeList.map { ($0.id, $0.name, $0.age) }
Although not sure why your id is String type... usually ID's are Int

Copy one struct object

i have to quite similar struct objects. but one includes more values than the other. As the initial is required for KituraKuery methods i can not modify it but require more information for future processing.
my problem is now, that these struct objects look like this:
struct provider: Codable {
var firstName: String?
var lastName: String?
var email:String?
}
extension provider: Model{
class Persistence {}
}
struct provider2: Codable {
var firstName: String?
var lastName: String?
var email:String?
var providerCategories: [categories]?
}
extension provider: Model{
class Persistence {}
}
what i need is basically a smarter way to copy information from provider to provider2.
what i did as of now is i provided an init to provider2 taking provider as input and adding all values to it.
struct provider2: Codable {
var firstName: String?
var lastName: String?
var email:String?
var providerCategories: [categories]?
init(provider: provider?) {
if let provider = provider{
firstName = provider.firstName
lastName = provider.lastName
email = provider.lastName
}
}
extension provider: Model{
class Persistence {}
}
i however believe this is probably the worst way and there are much better and more lean approaches to it.
I tried myself on protocols but could that not really get to work.
Any input would be great :)
In your approach both Provider and Provider2 struct are tightly coupled to each other. So lets say in future if you want to change Provider struct or you want to initialise Provider2 struct with another struct, then you need to change lot of things.
We can solve the problem easily by decoupling both Provider and Provider2 struct
protocol BasicInfo {
var firstName: String? { get set }
var lastName: String? { get set }
var email:String? { get set }
}
protocol Address {
var address: String? {get set}
}
struct Provider: BasicInfo {
var firstName: String?
var lastName: String?
var email: String?
}
struct Provider2: BasicInfo, Address {
var firstName: String?
var lastName: String?
var email:String?
var address: String?
init(basic: BasicInfo, add: String) {
firstName = basic.firstName
lastName = basic.lastName
email = basic.email
address = add
}
}
//Below are instances of respective struct
let provider1 = Provider(firstName: "Test1", lastName: "TestLast1", email: "test1#gmail.com")
var provider2 = Provider2(basic: provider1, add: "Germany")
In above code i have two different Struct Provider and Provider2. Provider2 contains more variable than Provider (i have just added a single var to demonstrate). Now lets say in future we don't require Provider to fill Provider2, we have a new struct Provider3 which will fill Provider2 values.
struct Provider3: BasicInfo {
var firstName: String?
var lastName: String?
var email: String?
var middleName: String? //new property added
}
//Below are instances of respective struct
let provider3 = Provider3(firstName: "Test1", lastName: "TestLast1", email: "test1#gmail.com")
var provider2 = Provider2(basic: provider3, add: "Germany")
As you see there is no changes in struct Provider2, we have just introduce a new struct, create instance of new struct and passed that instance to Provider2 init method.
You could use extensions for this:
extension provider {
func asProvider2() -> provider2 {
return provider2(firstName: firstName,
lastName: lastName,
email: email,
providerCategories: nil)
}
}
// Then you can use it like this:
let bar = provider(firstName: "foo", lastName: "bar", email: "baz")
let bar2 = bar.asProvider2()

Return partial object in Vapor 3

I would like to return a partial object in a response for another object type.
For example, I have a UserProfile model:
var id: Int?
var email: String
var firstName: String?
var lastName: String?
and an Adult model:
var id: Int?
var nickname: String
var type: String
var user: User.UserProfile
var family: Family
Say I would like to return just the UserProfile's email address in the Adult response, what is the way to go about that?
I have tried an approach with child/parent relationships, where my Adult model is more like:
var id: Int?
var nickname: String
var type: String
var user: User.ID
var family: Family
..but then my response just contains an object ID, but I really want to return a partial (or even full in some cases) object.
Thanks in advance.
The way this is done is to create a 'public' definition of your model, which will represent the JSON you return from your route.
For your model, you might create a struct like this:
struct AdultResponse: Content {
var id: Int?
var nickname: String
var type: String
var email: String
var family: Family
init(adult: Adult) {
self.id = adult.id
self.nickname = adult.nickname
self.type = adult.type
self.email = adult.user.email
self.family = adult.family
}
}
You can then get your Adult model from the database, create an AdultResponse and return that from your route.