I have a User object..
class User: NSObject {
var uid: String!
var handle: String!
var name: String!
var profilePicture: String!
var gender: String!
var rooms: [String : AnyObject]!
}
.. which has its values set when the user signs up for the app, using the below function to set the values in both Firebase and the User object:
// Set inital user info to User object & Firebase
func setUserInfo() {
let userInit = User()
let userRef: FIRDatabaseReference = FIRDatabase.database().reference().child("users").childByAutoId()
let params = ["fields" : "first_name"]
let graphRequest = GraphRequest(graphPath: "me", parameters: params)
graphRequest.start {
(urlResponse, requestResult) in
switch requestResult {
case .failed(let error):
print("error in graph request:", error)
break
case .success(let graphResponse):
if let responseDictionary = graphResponse.dictionaryValue {
print(responseDictionary)
// Name
if let name = responseDictionary["first_name"] {
userRef.child("name").setValue(name)
// Profile pic
let facebookID: NSString = (responseDictionary["id"] as! NSString)
let profilePic = "https://graph.facebook.com/\(facebookID)/picture?type=large&return_ssl_resources=1"
userRef.child("profilePicture").setValue(profilePic)
// Handle
// Also check DB to make sure handle isn't already in use
if self.handleTextField.text != nil {
if let handle = self.handleTextField.text {
userRef.child("handle").setValue(handle)
// Gender
var gender = ""
switch self.genderString {
case "male":
gender = "male"
userRef.child("gender").setValue("male")
case "female":
gender = "female"
userRef.child("gender").setValue("female")
default:
gender = "other"
userRef.child("gender").setValue("other")
}
// UID
if let uid = FIRAuth.auth()?.currentUser?.uid {
userInit.uid = uid
userRef.child("uid").setValue(uid)
print("uid: \(uid)")
}
// Set all values to User object
userInit.name = name as! String
userInit.handle = handle
userInit.gender = gender
userInit.profilePicture = profilePic
self.user.append(userInit)
print("name: \(name)")
print("handle: \(handle)")
print("gender: \(gender)")
print("profilePic: \(profilePic)")
}
}
}
}
}
}
}
With this, all the user info is uploaded to Firebase just fine. However when I try to print the values of the User object in the next view controller:
let user = [User]()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let users = User()
print("name: \(users.name)")
print("handle: \(users.handle)")
print("gender: \(users.gender)")
print("profilePic: \(users.profilePicture)")
}
All are printed as nil. Are the values not getting set to the object, or am I trying to access them wrong?
The point is that you are creating new empty class object in viewDidAppear(_ animated: Bool)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let users = User() //you created new empty object of User Type
print("name: \(users.name)")
print("handle: \(users.handle)")
print("gender: \(users.gender)")
print("profilePic: \(users.profilePicture)")
}
and printing all values will give you nil as it is empty. So way which will work is to pass userInit object to second view controller having constant var myUser
var myUser:User!
in prepareForSegue from fristViewController to second you can supply user Object so hereby the code for secondVC class will become
SecondViewController.swift
var myUser:User!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let users = User() //you created new empty object of User Type
users = myUser
print("name: \(users.name)")
print("handle: \(users.handle)")
print("gender: \(users.gender)")
print("profilePic: \(users.profilePicture)")
}
Related
I am trying to recreate the instagram follow and unfollow functionality. When the follow button is pressed, I call the follow function in the user.swift file. The user-followers structure works perfectly but the user-following database call does not seem to work. Both have the same logic, just opposite declarations. This might sound vague but the code is self-explanatory.
user-followers structure works perfectly but user-following structure does not seem to get created at firebase.
class User{
var username: String!
var name: String!
var profileImageUrl: String!
var uid: String!
var isFollowed = false
init(uid: String, dictionary: Dictionary<String, AnyObject>){
self.uid = uid
if let username = dictionary["username"] as? String {
self.username = username
}
if let name = dictionary["name"] as? String {
self.name = name
}
if let profileImageUrl = dictionary["profileImageUrl"] as?
String {
self.profileImageUrl = profileImageUrl
}
}
func follow(){
guard let currentUid = Auth.auth().currentUser?.uid else {
return }
// set is followed to true
self.isFollowed = true
// add followed user to current user-following structure
Database.database().reference().child("user-
following").child(currentUid).updateChildValues([self.uid: 1])
// add current user to followed user-follower structure
Database.database().reference().child("user-
followers").child(self.uid).updateChildValues([currentUid: 1])
}
func unfollow(){
guard let currentUid = Auth.auth().currentUser?.uid else {
return }
// set is followed to false
self.isFollowed = false
// remove user from current user-following structure
Database.database().reference().child("user-
following").child(currentUid).child(self.uid).removeValue()
// remove current user from user-follower structure
Database.database().reference().child("user-
followers").child(self.uid).child(currentUid).removeValue()
}
)
I am attempting to simply read into the database that is structured as stated below. I am attempting to read the user's "userType" and use it in the following if statements below. Any help is appreciated!
Swift Code:
// Create firebase reference and link to database
var dataRef : DatabaseReference?
dataRef = Database.database().reference()
let userID = Auth.auth().currentUser!.uid // Get the User's ID
// Gather user's type (Customer or Company)
/*Use this space to gather the user's type into some variable named currUserType*/
if (currUserType == "Customer"){
self.performSegue(withIdentifier: "LoginToCustomer", sender: self)
print("User: " + userID + " has been signed in!")
}
else if (currUserType == "Company"){
self.performSegue(withIdentifier: "LoginToHost", sender: self)
}
else{
self.showMessage(alertTitle: "Error",
alertMessage: "Please report the following error with a description of what lead to to the error.",
actionTitle: "Dismiss")
}
Database Structure:
"Users" : {
"ZFH0lFe1fIb5bwSO2Q95ektD33L2" : {
"email" : "cust#test.com",
"userType" : "Customer"
}
First take the ref like i have took below:
let dbRef = Database.database().reference().child("Users")
Then create model like i have created below:
class Users {
var email: String?
var userType: String?
init(email: String, userType: String) {
self.email = email
self.userType = userType
}
}
Then create completion Handler like i have created below:
func getUsersData(handler: #escaping (_ usersArray: [Users]) -> ()) {
var usersArray = [Users]()
dbRef.observe(.value) { (datasnapshot) in
guard let usersnapshot = datasnapshot.children.allObjects as? [DataSnapshot] else { return }
for user in usersnapshot {
let email = user.childSnapshot(forPath: "email").value as! String
let userType = user.childSnapshot(forPath: "userType").value as! String
let userObj = Users(email: email, userType: userType)
usersArray.append(userObj)
}
handler(usersArray)
}
}
simply call this function which returns the whole array of users.
Refrence https://firebase.google.com/docs/database/ios/read-and-write#reading_and_writing_data
I am trying to display the user data in screen. But I always get an empty value. I don't know why.
var profileData = Profile(usrObj: [String:String]())
#IBOutlet weak var userName: UILabel!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
self.userName.text = profileData.FirstName
print(profileData.FirstName)
}
My print statement and my label value are empty. Please help me out with any mistake I am making.
My model class :
class Profile {
var FirstName: String
init(usrObj : [String: AnyObject]) {
self.FirstName = (usrObj["FirstName"] ?? "") as! String
}
var ProfileObject: [String:AnyObject] {
return ["FirstName" : self.FirstName]
}
In your LoginViewController save your data in NSUserDefaults
#IBAction func loginWithUserNamePassword(){
KRProgressHUD.show(progressHUDStyle: .White, message: "Loading...")
loginWithMailAndPassword((username.text?.trimWhiteSpace)!, password: (password.text?.trimWhiteSpace)!) { (user, error) in
if error != nil{
KRProgressHUD.dismiss()
SCLAlertView().showError("Login Error", subTitle: error!.localizedDescription)
}
else {
if user!.emailVerified
{
currentUser = user
fireBaseRef.child("Users").child(currentUser!.uid).child("UserProfile").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
if let data: [String : AnyObject] = snapshot.value as? [String : AnyObject] {
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(data, forKey: "userdata")
userDefaults.synchronize()
enableSync()
self.navigateToNextScreen()
}
else{
}
})
}
else
{
SCLAlertView().showError("Login Error", subTitle: "This email is has not been verified yet")
}
}
}
}
and use that data in UserStaticDataViewController
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
self.profileDetailsExists = true
let userdata : NSDictionary = NSUserDefaults.standardUserDefaults().valueForKey("userdata") as! NSDictionary
print(userdata["City"] as? String)
self.userName.text = userdata["FirstName"] as? String
self.userCity!.text = userdata["City"] as? String
self.userCountry!.text = userdata.valueForKey("Country") as? String
self.userState.text = userdata.valueForKey("State") as? String
self.userMobileNo.text = userdata.valueForKey("Mobile") as? String
self.userGmail.text = userdata.valueForKey("Email") as? String
self.userDob.text = userdata.valueForKey("DateOfBirth") as? String
}
Output:
Just approve my answer and give vote.
Happy coding.
From the fact that your print statement is empty, it means that the userObject you pass into the following equation
var profileData = Profile(usrObj: [String:String]())
probably does not have a string value for the key "firstName".
You can try to verify this by changing your code
self.FirstName = (usrObj["FirstName"] ?? "") as! String
to
self.FirstName = (usrObj["FirstName"] ?? "Hello world") as! String
and see if "Hello world" is printed out in your console.
If yes, then you just have to make sure that the "user" object you pass into the init function of Profile class should be a dictionary where a value is stored for the key "FirstName"
I'm trying to get access to the values stored in firebase dashboard to use them in different functions and methods in the class.
I used this method in this question
I have tried to print their values, the whole app has crashed and it gave me that their nil!
They are not nil actually!
I used a similar method in viewDidLoad and I could retrieve the values to labels!
let refer = FIRDatabase.database().reference().child("UserDevices")
var globalEmail : String!
var globalPhone : String!
var globalImageUrl: String!
override func viewWillAppear(_ animated : Bool){
super.viewWillAppear(animated)
retrieveUserData{(email,phone,ImageUrl) in
self.globalEmail = email
self.globalPhone = phone
self.globalImageUrl = ImageUrl
}
}
func retrieveUserData(_ completionBlock : #escaping ((_ email : String?, _ phone : String?, _ ImageUrl: String?)->Void)){
refer.child(byAppendingPath: self.strUserid as String).observe(.value , with: {snapshot in
if let userDict = snapshot.value as? [String:AnyObject] {
completionBlock(userDict["email"] as! String, userDict["phone"] as! String, userDict["ImageUrl"] as! String)
}
})
}
var strUserid : NSString!
override func viewDidLoad() {
super.viewDidLoad()
print(globalEmail)
print(globalImageUrl)
print(globalPhone)
self.navigationController?.navigationBar.tintColor = UIColor.white
print("idis \(self.strUserid)")
let ref = FIRDatabase.database().reference().child("UserDevices")
self.navigationController?.navigationBar.tintColor = UIColor.white
ref.child(byAppendingPath: self.strUserid as String).observe(.value, with: { snapshot in
if let dict = snapshot.value as? NSMutableDictionary{
print("dict is \(dict)")
if let Provider = dict["name"] as? String
{
self.DeviceDetailsProvider.text = Provider
// self.navigationItem.title = Provider
}
if let name = dict["DeviceName"] as? String
{
self.DeviceDetailsName.text = name
self.navigationItem.title = name
}
if let ShortDescription = dict["Description"] as? String
{
self.DeviceDetailsDescription.text = ShortDescription
}
if let City = dict["city"] as? String
{
self.DeviceDetailsCity.text = City
}
}
})
self.DeviceDetailsImageView.downloadedFrom(link: globalImageUrl)
}
Why I'm getting a crash here!
Change ref.child(byAppendingPath: self.strUserid as String)
To:-
ref.child(self.strUserid)
Also remove let refer = FIRDatabase.database().reference().child("UserDevices").
You can not initialise your reference globally outside a scope because you don't know in which order your classes are being initialised, and probable scenario is that your FIRDatabase hasn't even been initialised yet when you try to initialise let refer.
Instead of refer in retrieveUserData use
FIRDatabase.database().reference().child("UserDevices")
You see in a viewController's LIFE CYCLE, viewdidLoad is called before than viewWillAppear:
So what you need is:-
override func viewDidLoad() {
super.viewDidLoad()
..
retrieveUserData{(email,phone,ImageUrl) in
self.globalEmail = email
self.globalPhone = phone
self.globalImageUrl = ImageUrl
self.DeviceDetailsImageView.downloadedFrom(link: globalImageUrl)
// .. Do your stuff...
}
}
Read: Viewcontroller's Lifecycle
When a user signs in, their UID is set to standardUserDefaults(). Also, the users' profile data is saved under a child named their uid.
When the user creates a post, I would like to attach their username/display name to the post.
I've set up a function to fetch the current user's username, but whenever I submit a post, it seems as though the closure is not being executed.
The post model:
class PostModel {
var postBody = String()
var creationDate = String()
var postUID = String()
var userName = String()
init(postBody: String) {
self.postBody = postBody
let dateObject = NSDate()
let formatDate = timeToString(dateObject)
self.creationDate = formatDate
let userID = NSUserDefaults.standardUserDefaults().valueForKey("uid") as! String
self.postUID = userID
self.userName = getUsername(userID)
}
// Used to convert the model to json compatible before saving
func postToDictionary() -> NSDictionary {
let jsonBody = postBody
let jsonDate = creationDate
let jsonUID = postUID
let jsonUsername = userName
let postAsDictionary = ["Body": jsonBody, "Timestamp": jsonDate, "UID": jsonUID, "Display Name": jsonUsername]
return postAsDictionary
}
}
and the function to get the username:
func getUsername(withUID: String) -> String {
var userName = String()
DataService.ref.userRef.childByAppendingPath(withUID).observeSingleEventOfType(.Value, withBlock: { snapshot in
userName = snapshot.value.objectForKey("Display Name") as! String
})
return userName
}
I set up my login function to get the current user's display name and set it to the standardUserDefaults which worked. I believe this is my solution unless someone has a better suggestion
#IBAction func loginButton(sender: AnyObject) {
if emailField != nil && passwordField != nil {
let emailAttempt = emailField.text!
let passwordAttempt = passwordField.text!
DataService.ref.baseRef.authUser(emailAttempt, password: passwordAttempt) {
error, authData in
if error != nil {
print("error in data check")
} else {
let returnUID = authData.uid
NSUserDefaults.standardUserDefaults().setValue(returnUID , forKey: "uid")
DataService.ref.userRef.childByAppendingPath(returnUID).childByAppendingPath("Display Name").observeSingleEventOfType(.Value, withBlock: { snapshot in
let UserDisplayName = snapshot.value as! String
NSUserDefaults.standardUserDefaults().setValue(UserDisplayName, forKey: "displayName")
self.performSegueWithIdentifier("loginSuccessSegue", sender: sender)
})
}
}
} else {
print("error")
return
}
}