Search code examples
swiftdatabasemodelmember

Why Isn't My Model Showing Its Member in View Controller?


I have a model called Profile with 2 members posPoints and negPoints. I'm trying to display the points for the current user on a VC called MyProfileViewController. When I type profiles.posPoints however, Xcode doesn't recognize it and gives me this error

Value of type '[Profile]' has no member 'posPoints'

static func show(for user: User = User.current, completion: @escaping (Profile?) -> Void) {

    let profileRef = Database.database().reference().child("profile").child(user.username)
    let ref = Database.database().reference().child("profile").child(user.username).child(profileRef.key ?? "")

    ref.observeSingleEvent(of: .value, with: { (snapshot) in
        guard let profile = Profile(snapshot: snapshot) else {
            return completion(nil)
        }

        completion(profile)
    })
}

import Foundation
import FirebaseDatabase.FIRDataSnapshot

class Profile {

    // MARK - Properties

    var key: String?
    let posPoints: Int
    let negPoints: Int

    init?(snapshot: DataSnapshot) {
        guard !snapshot.key.isEmpty else {return nil}
        if let dict = snapshot.value as? [String : Any]{

            let posPoints = dict["posPoints"] as? Int
            let negPoints = dict["negPoints"] as? Int

            self.key = snapshot.key
            self.posPoints = posPoints ?? 0
            self.negPoints = negPoints ?? 0
        }
        else{
            return nil
        }
    }
}

(In viewDidLoad of MyProfileViewController)

ProfileService.show { [weak self] (profiles) in
        self?.profiles = profiles
    }
    myPointsLabel.text = profiles.posPoints
}

Firebase Database View

Firebase Database


Solution

  • You have following issues with your code in viewDidLoad.

    1- Update myPointsLabel inside the completionHandler where fetching profiles is done.

    2- UI updates should be done on the Main thread.

    3- First, extract the desired profile from the array of profiles, then access points and convert it to String.

    Your code should look like this,

    var profile: Profile?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        ProfileService.show { [weak self] (profile) in
            self?.profile = profile
    
            if let points = profile?.posPoints {
                DispatchQueue.main.async {
                   self?.myPointsLabel.text = String(points)
                }
            }
        }
    }