So I am having an issue with my code. My signup page grabs the user data. It gets the username, location, and profile pic. Everything works right it seems everything is being saved to firebase. However when the account is created and I go to the user profile everything seems to be nil.
This is my function that handles the sign up.
#objc func handleSignUp(){
// first we cant to take sure that all of the fields are filled
let bio: String = ""
var profilePic: String = ""
// will take the user selected image and load it to firebase
let imageName = NSUUID().uuidString
let storageRef = Storage.storage().reference().child("profile_images").child("\(imageName).PNG")
if let userImage = selectedImageFromPicker,let uploadData = UIImageJPEGRepresentation(userImage, 0.1){
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil{
print(error ?? "")
return
}
profilePic = (metadata?.downloadURL()!.absoluteString)!
guard let username = self.nameTextField.text,
let confirmPassword = self.confirmPasswordTextField.text,
let email = self.emailTextField.text,
let password = self.passwordTextField.text,
!username.isEmpty,
!email.isEmpty,
!password.isEmpty,
!confirmPassword.isEmpty
else {
print("Required fields are not all filled!")
return
}
if self.validateEmail(enteredEmail:email) != true{
let alertController = UIAlertController(title: "Error", message: "Please Enter A Valid Email", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
// will make sure user is validated before it even tries to create user
// will make sure the password and confirm password textfields have the same value if so it will print an error
if self.passwordTextField.text != self.confirmPasswordTextField.text {
let alertController = UIAlertController(title: "Error", message: "Passwords Don't Match", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
// will authenticate a user into the authentication services with an email and passowrd
AuthService.createUser(controller: self, email: email, password: password) { (authUser) in
guard let firUser = authUser else {
return
}
//will add user to the database
print(profilePic)
print(username)
UserService.create(firUser, username: username , profilePic: profilePic , bio: bio, location: self.userLocation!) { (user) in
guard let user = user else {
print("User successfully loaded into firebase db")
return
}
// will set the current user for userdefaults to work
print(user.profilePic)
print(user.username)
User.setCurrent(user, writeToUserDefaults: true)
// self.delegate?.finishSigningUp()
self.finishSigningUp()
}
}
})
}
}
This is my viewdidload for the profile controller. When I print out the user here everything is nil.
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.white
let user = self.user ?? User.current
profileHandle = UserService.observeProfile(for: user) { [unowned self](ref, user, events) in
self.profileRef = ref
self.user = user
self.userEvents = events
// self.jobs = allJobs
// self.reciepts = allReciepts
// print(self.userEvents)
// print(self.reciepts)
DispatchQueue.main.async {
self.collectionView?.reloadData()
}
}
This handles the transition to the homepage.
func finishSigningUp() {
print("Finish signing up from signup view controller")
print("Attempting to return to root view controller")
let homeController = HomeViewController()
//should change the root view controller to the homecontroller when done signing up
self.view.window?.rootViewController = homeController
self.view.window?.makeKeyAndVisible()
}
My home view controller controls the navigation of these throguh a snapcaht style swiping which is controlled using an array of view controllers. Like so
lazy var viewControllerList: [UIViewController] = {
let homeFeedController = HomeFeedController()
let navController = UINavigationController(rootViewController: homeFeedController)
// let navController = ScrollingNavigationController(rootViewController: homeFeedController)
let profileView = ProfileeViewController(collectionViewLayout: UICollectionViewFlowLayout())
let profileViewNavController = UINavigationController(rootViewController: profileView)
let searchController = EventSearchController(collectionViewLayout: UICollectionViewFlowLayout())
let searchNavController = UINavigationController(rootViewController: searchController)
return [searchNavController,navController,profileViewNavController]
}()
Obseverprofile function
// will observe the user object in the database for any changes and make sure that they are updated
static func observeProfile(for user: User, completion: #escaping (DatabaseReference, User?, [Event]) -> Void) -> DatabaseHandle {
// 1
let userRef = Database.database().reference().child("users").child(user.uid)
// 2
return userRef.observe(.value, with: { snapshot in
// 3
guard let user = User(snapshot: snapshot) else {
return completion(userRef, nil, [])
}
// print(user)
// 4
Events(for: user, completion: { events in
// 5
completion(userRef, user, events)
})
})
}
User Model
import Foundation
import FirebaseDatabase.FIRDataSnapshot
class User : NSObject {
//User variables
let uid : String
let username : String?
let profilePic: String?
var location: String?
var isFollowed = false
let bio: String?
var dictValue: [String : Any] {
return ["username" : username as Any,
"profilePic" : profilePic as Any,
"Bio" : bio as Any, "location": location as Any]
}
//Standard User init()
init(uid: String, username: String, profilePic: String, bio: String, location: String = "") {
self.uid = uid
self.username = username
self.profilePic = profilePic
self.bio = bio
self.location = location
super.init()
}
//User init using Firebase snapshots
init?(snapshot: DataSnapshot) {
guard let dict = snapshot.value as? [String : Any],
let username = dict["username"] as? String,
let profilePic = dict["profilePic"] as? String,
let bio = dict["bio"] as? String,
let location = dict["location"] as? String
else { return nil }
self.uid = snapshot.key
self.location = location
self.username = username
self.profilePic = profilePic
self.bio = bio
}
//UserDefaults
required init?(coder aDecoder: NSCoder) {
guard let uid = aDecoder.decodeObject(forKey: "uid") as? String,
let username = aDecoder.decodeObject(forKey: "username") as? String,
let profilePic = aDecoder.decodeObject(forKey: "profilePic") as? String,
let bio = aDecoder.decodeObject(forKey: "bio") as? String,
let location = aDecoder.decodeObject(forKey: "location") as? String
else { return nil }
self.uid = uid
self.username = username
self.profilePic = profilePic
self.bio = bio
self.location = location
super.init()
}
init?(key: String, postDictionary: [String : Any]) {
//var dict : [String : Any]
//print(postDictionary as? [String:])
let dict = postDictionary
print(dict)
let profilePic = dict["profilePic"] as? String ?? ""
let bio = dict["bio"] as? String ?? ""
let username = dict["username"] as? String ?? ""
let location = dict["location"] as? String ?? ""
self.uid = key
self.location = location
self.profilePic = profilePic
self.username = username
self.bio = bio
}
//User singleton for currently logged user
private static var _current: User?
static var current: User {
guard let currentUser = _current else {
fatalError("Error: current user doesn't exist")
}
return currentUser
}
class func setCurrent(_ user: User, writeToUserDefaults: Bool = true) {
print(user)
print("")
if writeToUserDefaults {
let data = NSKeyedArchiver.archivedData(withRootObject: user)
UserDefaults.standard.set(data, forKey: "currentUser")
UserDefaults.standard.synchronize()
}
_current = user
print(_current)
}
}
extension User: NSCoding {
func encode(with aCoder: NSCoder) {
aCoder.encode(uid, forKey: "uid")
aCoder.encode(username, forKey: "username")
aCoder.encode(profilePic, forKey: "profilePic")
aCoder.encode(bio, forKey: "bio")
aCoder.encode(location, forKey: "location")
}
}
Related
I have a bit of a lengthy question, So I apologize in advance I will try to illustrate this to the best of my abilities. I am trying to establish a notifications view controller that calls different types of data from Firebase and sets different notification types.
In the image above, this is how the cells should look when a user sends a notification to firebase. The user associated with that specific notification type as called and posted onto the screen.
In the firebase structure, We see that all of the information Stored is saved under the UID of the user in the first picture and is set under that specific users notification to show who is sending them a notification which is correct. These users names and images show perfectly as well as the image on the right.
The code I use to save this information is below,
fileprivate func saveSwipeToDataBase(didLike: Any) {
let swipeDate = Int(NSDate().timeIntervalSince1970)
guard let uid = Auth.auth().currentUser?.uid else { return }
guard let cardUID = topCardView?.cardViewModel.uid else { return }
let documentData = ["workerId": uid,
"didLike": didLike,
"checked": 0,
"Swipe Date": swipeDate,
"type": SWIPE_INT_VALUE,
"posterId" : cardUID] as [String : Any]
self.postJobNotificationsIntoDatabseWithUID(uid: cardUID, values: documentData as [String : AnyObject])
}
private func postJobNotificationsIntoDatabseWithUID(uid: String, values: [String: AnyObject]) {
let ref = Database.database().reference(fromURL: "https://oddjobs-b131f.firebaseio.com/")
let usersReference = ref.child("notifications").child(uid).childByAutoId()
usersReference.setValue(values, withCompletionBlock: { (err, ref) in
if err != nil {
print("error saving data into firebase")
return
}
})
}
And below is how I retrieve this information and store it onto the Notifications View controller.
func fetchNotifications() {
guard let currentUID = Auth.auth().currentUser?.uid else { return }
NOTIFICATIONS_REF.child(currentUID).observeSingleEvent(of: .value) { (snapshot) in
guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
print(dictionary)
for (_, postingRawData) in dictionary {
guard let postingDictionary = postingRawData as? Dictionary<String, AnyObject> else { continue }
guard let uid = postingDictionary["workerId"] as? String else { continue }
Database.fetchUser(with: uid, completion: { (user) in
if let postId = postingDictionary["posterId"] as? String {
Database.fetchPoster(with: postId, completion: {(poster) in
let notification = userNotifications(user: user, poster: poster, dictionary: postingDictionary)
self.notifications.append(notification)
self.handleSortNotification()
})
} else {
let notification = userNotifications(user: user, dictionary: postingDictionary)
self.notifications.append(notification)
self.handleSortNotification()
}
})
}
}
}
Now that I got the correct way to setup up and show out of the way, I will show my enum and how I am distinguishing the different types of calls from firebase.
class userNotifications {
// MARK: - establish notificationTypes
enum NotificationType: Int, Printable {
case swipe
case accepted
case confirmed
case completed
case pay
var description: String {
switch self {
case .swipe: return " swiped on your Job "
case .accepted: return " accepted you to complete the job, "
case .confirmed: return " confirmed the job"
case .completed: return " completed the job"
case .pay: return " pay for completed"
}
}
init(index: Int) {
switch index {
case 0: self = .swipe
case 1: self = .accepted
case 2: self = .confirmed
case 3: self = .completed
case 4: self = .pay
default: self = .swipe
}
}
}
// MARK: - access firebaseData
var creationDate: Date!
var timeDate: Date!
var uid: String!
var fromId: String?
var workerId: String?
var user: User!
var poster: Poster!
var type: Int?
var notificationType: NotificationType!
var didCheck = false
init(user: User? = nil, poster: Poster? = nil, dictionary: Dictionary<String, AnyObject>) {
self.user = user
if let poster = poster {
self.poster = poster
}
if let swipeDate = dictionary["Swipe Date"] as? Double {
self.creationDate = Date(timeIntervalSince1970: swipeDate)
}
if let createDate = dictionary["creationDate"] as? Double {
self.creationDate = Date(timeIntervalSince1970: createDate)
}
if let swipeDate = dictionary["time&date"] as? Double {
self.timeDate = Date(timeIntervalSince1970: swipeDate)
}
if let type = dictionary["type"] as? Int {
self.notificationType = NotificationType(index: type)
}
if let uid = dictionary["uid"] as? String {
self.uid = uid
}
if let fromId = dictionary["fromId"] as? String {
self.fromId = fromId
}
if let workerId = dictionary["workerUID"] as? String {
self.workerId = workerId
}
if let checked = dictionary["checked"] as? Int {
if checked == 0 {
self.didCheck = false
} else {
self.didCheck = true
}
}
}
}
Above is the different types of notifications to be set.
Now, My issue is If I call a different notification type, such as .accepted, the information calls in a very different way.
The image above seems correct, However, the name and image are incorrect. it should be from the user ZacheryWilcox instead of Cjbwjdhbe. the user Cjbwjdhbe is the current user and the user who should be receing a notification from Zacherywilcox. not from itself.
In firebase, the information is saved as
the code I use to save this information is below
var workerUser: User? {
didSet {
let name = workerUser?.name
workerNameLabel.text = name
let workersUID = workerUser?.uid
workerNameLabel.text = name
guard let profileImage = workerUser?.profileImageUrl else { return }
workerImageView.loadImageUsingCacheWithUrlString(profileImage)
}
}
func saveUserData() {
let workUser = self.workerUser
guard let uid = Auth.auth().currentUser?.uid else { return }
let workerId = workUser?.uid
Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String : Any] else { return }
let user = User(dictionary: dictionary as [String : AnyObject])
workUser?.uid = snapshot.key
self.datePicker.datePickerMode = UIDatePicker.Mode.date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM dd yyyy/ hh:mm a"
let selectedDate = dateFormatter.string(from: self.datePicker.date)
let creationDate = Int(NSDate().timeIntervalSince1970)
print(selectedDate)
let docData: [String: Any] = [
"workerId": workerId!,
"time&date": selectedDate,
"posterId" : uid,
"creationDate": creationDate,
"location": user.address!,
"type": 1,
"jobPost": "someUIDString",
"checked": 0,
]
self.postJobNotificationsIntoDatabseWithUID(uid: workerId!, values: docData as [String : AnyObject])
}, withCancel: { (err) in
print("attempting to load information")
})
print("Finished saving user info")
self.dismiss(animated: true, completion: {
print("Dismissal complete")
})
}
private func postJobNotificationsIntoDatabseWithUID(uid: String, values: [String: AnyObject]) {
let ref = Database.database().reference(fromURL: "https://oddjobs-b131f.firebaseio.com/")
let usersReference = ref.child("notifications").child(uid).childByAutoId()
usersReference.setValue(values, withCompletionBlock: { (err, ref) in
if err != nil {
print("error saving data into firebase")
return
}
})
}
When the type .accepted is being used to differentiate what notificationType is being called, the user who sent the notification is not being set correctly and I have no idea what is the reasoning behind this. The correct user that is sending this information over is Zacherywilcox, and that users image and name should be set to the user's notification screen. not the user Cjbe... I was wondering if anyone could help me fix these issues. Thank you in advance. I'm starting to think that the way I am saving the users information when accepting the user is incorrect.
When I am fetchingNotifications(), is it possible that since calling
guard let uid = postingDictionary["workerId"] as? String else { continue }
Database.fetchUser(with: uid, completion: { (user) in
if let postId = postingDictionary["posterId"] as? String {
has an effect on whats going on? if so, Is there a way to differentiate between what notificationType is being called and fetch what notifications has been called with their respective users?
Just update your code to:
func fetchNotifications() {
guard let currentUID = Auth.auth().currentUser?.uid else { return }
NOTIFICATIONS_REF.child(currentUID).observeSingleEvent(of: .value) { (snapshot) in
guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
print(dictionary)
let notificationId = snapshot.key
for (_, postingRawData) in dictionary {
guard let postingDictionary = postingRawData as? Dictionary<String, AnyObject> else { continue }
guard let type = postingDictionary["type"] as? Int else { continue }
guard let uid = (type == userNotifications.NotificationType.accepted.rawValue) ? postingDictionary["fromId"] as? String : postingDictionary["workerId"] as? String else { continue }
Database.fetchUser(with: uid, completion: { (user) in
if let postId = postingDictionary["fromId"] as? String {
Database.fetchPoster(with: postId, completion: {(poster) in
let notification = userNotifications(user: user, poster: poster, dictionary: postingDictionary)
self.notifications.append(notification)
self.handleSortNotification()
})
} else {
let notification = userNotifications(user: user, dictionary: postingDictionary)
self.notifications.append(notification)
self.handleSortNotification()
}
// NOTIFICATIONS_REF.child(currentUID).child(notificationId).child("checked").setValue(1)
})
}
}
}
This will solve your problem.
This question already has answers here:
Returning data from async call in Swift function
(13 answers)
Closed 3 years ago.
Within my function to load users I'm able to retrieve a value. However, when I want to assign it to my variable outside the function it has nothing, as shown in the login function.
Load User Function
func loadUser(userid: String) -> User {
//print(userid)
let userid = "56ldZFJiv0dpfaABzo78"
var user = User()
let docRef = db.collection("users").document(userid)
docRef.getDocument { (document, error) in
if let document = document {
let first = document.data()!["first"] as! String
let last = document.data()!["last"] as! String
let position = document.data()!["position"] as! String
let company = document.data()!["company"] as! String
let email = document.data()!["email"] as! String
let address = document.data()!["address"] as! String
let userID = document.data()!["userID"] as! String
//Initalize user
user = User(userID: userID,
firstName: first,
lastName: last,
company: company,
address: address,
position: position,
email: email)
print(user.position)
} else {
print("Document does not exist")
}
}
return user
}
Login Function
//MARK: LOGIN
func login() {
Auth.auth().signIn(withEmail: emailField.text!, password: passwordField.text!) { (user, error) in
if error == nil{
//self.performSegue(withIdentifier: "loginToAdmin", sender: self)
//Load user
let loggedOnUser = self.loadUser(userid: Auth.auth().currentUser!.uid)
print(loggedOnUser.userID)
// let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
// let chatViewController = storyBoard.instantiateViewController(withIdentifier: "chatVC") as! UINavigationController
// self.present(chatViewController, animated: true, completion: nil)
}
else {
DispatchQueue.main.async{
//Display Alert Message if login failed
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
}
For the first function, I get a position value, as stated in the print statement.
For the second function, my variable, "loggedOnUser" is empty.
You need a completion as loadUser is asynchronous
func loadUser(userid: String,completion:#escaping(User?) ->()) {
//print(userid)
let userid = "56ldZFJiv0dpfaABzo78"
var user = User()
let docRef = db.collection("users").document(userid)
docRef.getDocument { (document, error) in
if let document = document {
let first = document.data()!["first"] as! String
let last = document.data()!["last"] as! String
let position = document.data()!["position"] as! String
let company = document.data()!["company"] as! String
let email = document.data()!["email"] as! String
let address = document.data()!["address"] as! String
let userID = document.data()!["userID"] as! String
//Initalize user
user = User(userID: userID,
firstName: first,
lastName: last,
company: company,
address: address,
position: position,
email: email)
print(user.position)
completion(user)
} else {
print("Document does not exist")
completion(nil)
}
}
}
Call
self.loadUser(userid: Auth.auth().currentUser!.uid) { res in
if let user = res {
print(user)
}
}
I am implementing a social media application using Swift. In the MyProfileViewController, I have used UIImagePickerController to change the current user's profile picture. However, usage of UIImagePickerController causes a duplicate of table view rows even though I handle the table view in viewDidLoad, not in viewWillAppear.
To illustrate, here is my viewDidLoad function.
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.automaticallyAdjustsScrollViewInsets = false
ref = Database.database().reference()
storageRef = Storage.storage().reference()
ref.child("users").child((Auth.auth().currentUser?.uid)!).observe(.value, with: {
(snapshot) in
let value = snapshot.value as? NSDictionary
let userId = value?["id"] as! String
let username = value?["username"] as! String
let email = value?["userEmail"] as! String
let profilePictureUrl = value?["profilePicture"] as! String
self.currentUser = User(id: userId, username: username, email: email, profilePicture: profilePictureUrl)
self.tableView.reloadData()
})
ref.child("posts").observe(.childAdded, with: {
(snapshot) in
let value = snapshot.value as? NSDictionary
let id = value?["id"] as! String
let tags = value?["tags"] as! String
let facultyName = value?["faculty"] as! String
let courseName = value?["course"] as! String
let questionTitle = value?["title"] as! String
let questionText = value?["description"] as! String
let dateAndTime = value?["dateAndTime"] as! String
let userID = value?["user-id"] as! String
self.ref.child("users").child(userID).observe(.value, with: {
(snapshot) in
let value = snapshot.value as? NSDictionary
let userId = value?["id"] as! String
let username = value?["username"] as! String
let email = value?["userEmail"] as! String
let profilePictureUrl = value?["profilePicture"] as! String
let post = Post(id: id, tags: tags, facultyName: facultyName, courseName: courseName, questionTitle: questionTitle, questionText: questionText, dateAndTime : dateAndTime, username: username)
if userID == Auth.auth().currentUser?.uid {
self.posts.insert(post, at: 0)
}
self.postDictionary[id] = post
let member = User(id: userId, username: username, email: email, profilePicture: profilePictureUrl)
if post.username == member.username {
self.userDictionary[id] = member
}
self.tableView.reloadData()
})
})
}
And here is my UIImagePickerController function:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let indexPath = NSIndexPath(row: 0, section: 0)
let cell = tableView.cellForRow(at: indexPath as IndexPath) as! MyProfileInfoCell!
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
selectedImage = image
cell?.profilePicture.contentMode = .scaleAspectFit
cell?.profilePicture.image = image
}
var data = NSData()
data = UIImageJPEGRepresentation((cell?.profilePicture.image!)!, 0.8)! as NSData
let filePath = "\((Auth.auth().currentUser?.uid)!)" // path where you wanted to store img in storage
let metaData = StorageMetadata()
metaData.contentType = "image/jpg"
self.storageRef = Storage.storage().reference()
self.storageRef.child(filePath).putData(data as Data, metadata: metaData) {
(metaData,error) in
if let error = error {
print(error.localizedDescription)
return
} else{
let downloadURL = metaData!.downloadURL()!.absoluteString
self.ref.child("users").child((Auth.auth().currentUser?.uid)!).updateChildValues(["profilePicture" : downloadURL])
}
}
self.dismiss(animated: true, completion: nil)
print(self.posts.count)
}
My table view consists of 2 prototype cells. The first prototype cell is for the profile information, in which changing profile picture is handled. The second prototype cell is for showing the posts posted by that user. The problem occurs here. When I change my profile picture, the posts rows are being duplicated.
Can anyone help me with this?
The observe method adds an observer to "users" on your DB. Every time you changes the "users" on DB the following code is executed and a post is added to tableview:
self.ref.child("users").child(userID).observe(.value, with: {
(snapshot) in
let value = snapshot.value as? NSDictionary
let userId = value?["id"] as! String
let username = value?["username"] as! String
let email = value?["userEmail"] as! String
let profilePictureUrl = value?["profilePicture"] as! String
let post = Post(id: id, tags: tags, facultyName: facultyName, courseName: courseName, questionTitle: questionTitle, questionText: questionText, dateAndTime : dateAndTime, username: username)
if userID == Auth.auth().currentUser?.uid {
self.posts.insert(post, at: 0)
}
self.postDictionary[id] = post
let member = User(id: userId, username: username, email: email, profilePicture: profilePictureUrl)
if post.username == member.username {
self.userDictionary[id] = member
}
self.tableView.reloadData()
})
When you update the profile picture the DB is updated too and the above code is executed. That is why the posts are duplicated. To fix that changes the method from observe to observeSingleEvent. The observeSingleEvent method requests data from DB once.
self.ref.child("users").child(userID).observeSingleEvent(.value, with: {
(snapshot) in
let value = snapshot.value as? NSDictionary
let userId = value?["id"] as! String
let username = value?["username"] as! String
let email = value?["userEmail"] as! String
let profilePictureUrl = value?["profilePicture"] as! String
let post = Post(id: id, tags: tags, facultyName: facultyName, courseName: courseName, questionTitle: questionTitle, questionText: questionText, dateAndTime : dateAndTime, username: username)
if userID == Auth.auth().currentUser?.uid {
self.posts.insert(post, at: 0)
}
self.postDictionary[id] = post
let member = User(id: userId, username: username, email: email, profilePicture: profilePictureUrl)
if post.username == member.username {
self.userDictionary[id] = member
}
self.tableView.reloadData()
})
I am not positive if I am structuring my app correctly. I am using structs for the first time and I am trying to save locations from users and create users using Firebase. I want to display all users only by location. The Global.refString gets set from a UIPicker which is hard coded with 6 different locations. loadUserInfo() is not returning any information. It worked the first time I tried it but after reopening and closing the app it always returns empty. Im not sure if a struct will get saved each time I open the app. Should I use a different method to accomplish these tasks.
private func saveUserInfo(firstLastName: String, user: User!, location: String, biography: String, password: String, phoneNumber: String){
let locationRef = Global.refString
let userInfo = ["firstLastName": firstLastName, "email": user.email!, "password": password, "location": location, "phoneNumber": phoneNumber, "biography": biography, "uid": user.uid, "photoURL": String(describing: user.photoURL!)] as [String : Any]
let userRef = dataBaseRef.child(locationRef!).child(user.uid)
userRef.setValue(userInfo) { (error, ref) in
if error == nil{
print("USER SAVED")
self.logIn(email: user.email!, password: password)
}else{
print(error?.localizedDescription)
}
}
}
func loadUserInfo(){
let locationRef = Global.refString
let userRef = dataBaseRef.child(locationRef!).child(Auth.auth().currentUser!.uid)
userRef.observe(.value, with: { (snapshot) in
let user = Users(snapshot: snapshot)
if let username = user.name{
self.nameLabel.text = username
}
if let number = user.phoneNumber{
self.phone = Int(number)
}
if let userLocation = user.location{
self.bioLabel.text = userLocation
}
self.storageRef.storage.reference(forURL: imageOld).getData(maxSize: 10 * 1024 * 1024, completion: { (imgData, error) in
if error == nil {
DispatchQueue.main.async {
if let data = imgData {
self.avatar.image = UIImage(data: data)
}
}
}else {
print(error!.localizedDescription)
}
}
)}
}) { (error) in
print(error.localizedDescription)
}
}
}
struct Global
{
static var Location : String!
static var usersListSent
= [String]()
static var refString: String!
}
Try:
Database.database().reference().child(Global.refString).child(id).observeSingleEvent(of: .value) { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
print(snap)
}
}
Im creating a profile for my app and when Im trying to delete the profile it won't delete from the view if I come back to it, In the other hand if I close the app and open it again the data would be gone. I can see the data been removed from the sqlite Database in my simulator.
override func viewDidLoad() {
super.viewDidLoad()
showDatePicker()
showPickerRanks ()
pickerRank.delegate = self
pickerRank.dataSource = self
sideMenus()
let appDelegate = UIApplication.shared.delegate as! AppDelegate // UIApplication.shared().delegate as! AppDelegate is now UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Profile")
request.returnsObjectsAsFaults = false
var isEmpty : Bool {
do {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Profile")
let count = try context.count(for: request)
return count == 0 ? true : false
} catch {
return true
}
}
if isEmpty == true {
//Check if there is a Profile
performSegue(withIdentifier: "NoProfileSegue", sender: nil)
} else {
print("No Files")
}
print("Database is empty:\(isEmpty)")
do {
let results = try context.fetch(request)
for result in results as! [NSManagedObject] {
if let airmanNameVar = result.value(forKey: "airmanName") as? String {
PersonName.text = airmanNameVar
}
if let airmanRankVar = result.value(forKey: "airmanRank") as? String {
AirmanRankPicker.text = airmanRankVar
}
if let airmanHeigthVar = result.value(forKey: "airmanHeight") as? Double {
HeightTxtLbl.text = String (airmanHeigthVar)
}
if let airmanWeightVar = result.value(forKey: "airmanWeight") as? Int64 {
weightTxtLbl.text = String (airmanWeightVar)
}
if let airmanAFPTScore = result.value(forKey: "airmanLastAFPTScore") as? Double {
LastAFPTScore.text = String(airmanAFPTScore)
}
if let airmanAFPTDateLast = result.value(forKey: "airmanLastAFTPData") as? String {
LastAFPTDate.text = airmanAFPTDateLast
}
and here is my Delete
#IBAction func DeleteBtn(_ sender: Any) {
let actionSheetController: UIAlertController = UIAlertController(title: "AF Fitness", message:"By pressing Delete all data would be erase.", preferredStyle: .actionSheet)
//Create and add the Cancel action
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in
}
actionSheetController.addAction(cancelAction)
let AgreeAction: UIAlertAction = UIAlertAction(title: "Delete", style: .default) { action -> Void in
self.resetAllRecords(in: "Profile")
self.deleteHistory()
UserDefaults.standard.set(false, forKey: "ProfileOn") //Bool Data Type
UserDefaults.standard.synchronize()
self.AgeGroupSeg.selectedSegmentIndex = 0
self.GenderSeg.selectedSegmentIndex = 0
UserDefaults.standard.set(0, forKey: "GenderData")
UserDefaults.standard.set(0, forKey: "AgeGroupData")
self.AirmanRankPicker.text = ""
self.PersonName.text = ""
self.weightTxtLbl.text = ""
self.HeightTxtLbl.text = ""
self.LastAFPTDate.text = ""
self.LastAFPTScore.text = ""
self.performSegue(withIdentifier: "NoProfileSegue", sender: nil)
// self.performSegue(withIdentifier: "NoProfileSegue", sender: nil)
}
actionSheetController.addAction(AgreeAction )
//Present the AlertController
self.present(actionSheetController, animated: true, completion: nil)
}
func resetAllRecords(in entity : String) // entity = Your_Entity_Name
{
let appDelegate = UIApplication.shared.delegate as! AppDelegate // UIApplication.shared().delegate as! AppDelegate is now UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Profile")
request.returnsObjectsAsFaults = false
let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
do {
try context.execute(deleteRequest)
try context.save()
} catch {
print ("There was an error")
}
}
Thank you in advance