I'm new to swift and firebase and am trying lots of things out. I have created a collection of "characters" in firebase which are displayed in the app. The aim is there are "characters" you unlock by earning points. Points are earned by walking (getting steps using HealthKit)
When a user taps on a character and then taps "unlock" its added to a struct called UnlockingCharacters.
UnlockingCharacters are shown in the users profile.
I need to make the UnlockingCharacters struct part of the users document on Firebase (maybe as a subcollection?)
I want to limit the number of characters in UnlockingCharacters to 2. Characters are unlocked by taking steps which are turned into points. When points are uploaded to firebase, the character receives these points and adds it to its total (a characters points total is the sum of all users that are unlocking the characters points).
Here is the Character Model:
struct Character: Identifiable, Decodable {
@DocumentID var id: String?
var character_name: String
var character_type: String
var character_image: String
var character_details: String
var character_usersUnlocking: Int
var character_totalPoints: Int
var user: UserModel?
var didUnlock: Bool? = false
// To identify whether it is being unlocked...
var isUnlocking: Bool = false
}
Here is the UnlockingCharacters model:
struct UnlockingCharacters: Identifiable {
var id = UUID().uuidString
var character: Character
}
SharedDataModel:
class SharedDataModel: ObservableObject {
// Unlocking Characters...
@Published var unlockingCharacters: [Character] = []
}
My Functions:
func isUnlocked() -> Bool {
return sharedData.unlockingCharacters.contains { characterData in
return self.characterData.id == characterData.id
}
}
func addToUnlocking() {
if let index = sharedData.unlockingCharacters.firstIndex(where: {
characterData in
return self.characterData.id == characterData.id
}){
// Remove from unlocking...
sharedData.unlockingCharacters.remove(at: index)
}
else {
// Add to unlocking...
sharedData.unlockingCharacters.append(characterData)
}
}
I know that something needs to be added to my UserModel too however I am getting an error:
struct UserModel: Identifiable, Decodable {
var username : String
var pic : String
var bio: String
var uid : String
var id: String { uid }
//I am getting error for the following variable:
(Value type 'UserModel' cannot have a stored property that recursively contains it)
var activeUnlockingCharacters: UnlockingCharacters
}
To sum up I need UnlockingCharacters to be added to the users document on Firebase.
CodePudding user response:
Get rid of var user: UserModel?
in Character
Then you can find the characters under activeUnlockingCharacters
or something like
UserModel/{uid}/UnlockingCharacters
You can make
var activeUnlockingCharacters: UnlockingCharacters
An Array
var activeUnlockingCharacters: [UnlockingCharacters]
Then use validation or rules to limit the count to 2
Firebase has a whole section on how to process custom objects.
https://firebase.google.com/docs/firestore/manage-data/add-data#custom_objects
if you have all your structs conform to Codable
do {
try db.collection("UserModel").document("\(uid)").setData(from: userModelObject)
} catch let error {
print("Error writing object to Firestore: \(error)")
}
And to read
https://firebase.google.com/docs/firestore/query-data/get-data
let docRef = db.collection("UserModel").document("\(uid)")
docRef.getDocument(as: UserModel.self) { result in
// The Result type encapsulates deserialization errors or
// successful deserialization, and can be handled as follows:
//
// Result
// /\
// Error UserModel
switch result {
case .success(let userModel):
// A `Model` value was successfully initialized from the DocumentSnapshot.
print("Model: \(userModel)")
case .failure(let error):
// A `Model` value could not be initialized from the DocumentSnapshot.
print("Error decoding object: \(error)")
}
}
You can also user the new @FirestoreQuery
and use rules to limit the object that is visible
Set in the rules that the user is the only one that can read its own UserModel based on auth.