Wenn sich ein Benutzer in der App anmeldet, werden einige Firebase-Beobachtungen, wie z. B. fetchSavedActionsForTracking() und fetchActionsForDowns() (siehe die folgenden vollständigen Funktionen), nicht beobachtet Klicken Sie auf Schaltflächen, und die App verhält sich seltsam, als würde sie sich mit Knoten in Firebase vermischen. Sobald ich den Code erneut kompiliere, funktioniert der Code perfekt und alles kehrt normal zurück. Ich bin mir nicht sicher, ob Xcode dieses Problem verursacht oder ob ich viele Beobachtungen in View Controller habe. Wenn jemand das gleiche Problem hat oder eine Idee hat, lass es mich wissen. Ich habe auch einige Beobachtungen in anderen VC, aber sie sind feinFirebase-Problem mit Beobachtung Sobald sich ein Benutzer angemeldet/angemeldet hat iOS
Hier werden die Beobachtungen ist, ich habe Ich bin View Controller:
func fetchProperties() {
// Added the first property
Database.database().reference().child("Properties").observe(.childAdded, with: { (snapshot) in
if let dictinaryProperty = snapshot.value as? [String: AnyObject]{
// Assign property to Property()
self.property = Property()
// set the variables in dictionaryProperty's value to property's value (Be carefull the names have to match)
self.property?.setValuesForKeys(dictinaryProperty)
// User ID in Firebase
self.property?.keyID = snapshot.key
// Then add it to arrayPropertys
self.arrayPropertys.append(self.property!)
// This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}, withCancel: nil)
// Remove
Database.database().reference().child("Properties").observe(.childRemoved, with: { (snapshot) in
if let dictinaryProperty = snapshot.value as? [String: AnyObject]{
// Assign property to Property()
self.property = Property()
// set the variables in dictionaryProperty's value to property's value (Be carefull the names have to match)
self.property?.setValuesForKeys(dictinaryProperty)
// User ID in Firebase
self.property?.keyID = snapshot.key
// Check on the loaded tracking
if self.arrayPropertysTracking.isEmpty != true {
// Then delete from Firebase
self.checkingAndDeletingTracking(remove: self.property!)
}
// Then add it to arrayPropertys
self.arrayPropertysRemoved.append(self.property!)
self.removedProperties()
// This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}, withCancel: nil)
// Child is edited
Database.database().reference().child("Properties").observe(.childChanged, with: { (snapshot) in
if let dictinaryProperty = snapshot.value as? [String: AnyObject]{
// Assign property to Property()
self.property = Property()
// set the variables in dictionaryProperty's value to property's value (Be carefull the names have to match)
self.property?.setValuesForKeys(dictinaryProperty)
// User ID in Firebase
self.property?.keyID = snapshot.key
// Check if the updated property exists in Tracking window and if it does update it too
if self.arrayPropertysTracking.isEmpty != true {
self.checkingAndUpdateTracking(update: self.property!)
}
// Then add it to arrayPropertys
self.arrayPropertiesEdited.append(self.property!)
self.editedProperties()
// This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}, withCancel: nil)
}
Zweite;
// Load saved actions of the current user
func fetchSavedActionsForTracking() {
let userID = Auth.auth().currentUser?.uid
if let actualUserID = userID {
// Add the first property
Database.database().reference().child("Actions For Tracking").child(actualUserID).observe(.childAdded, with: { (snapshot) in
// The key is the property owner's ID
let keySnapshot = snapshot.key as? String
// Tags of saved buttons
let valueSnapshot = snapshot.value as? String
if let actualKey = keySnapshot {
self.arraySavedKeyIDs.append(actualKey)
}
//This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}, withCancel: nil)
// Removed the saved actions in Firebase when a property delected in Tracking window
Database.database().reference().child("Actions For Tracking").child(actualUserID).observe(.childRemoved, with: { (snapshot) in
// The key is the property owner's ID
let keySnapshot = snapshot.key as? String
// Tags of saved buttons
let valueSnapshot = snapshot.value as? String
if let actualKey = keySnapshot {
self.arrayRemovedTags.append(actualKey)
}
// Remove the tag from the array
self.removedArrayTags()
// When saved is clicked twice clear the arrayRemovedTags
self.arrayRemovedTags.removeAll()
//This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}, withCancel: nil)
}
}
Dritte;
// Load properties from tracking window
func fetchTracking() {
let userID = Auth.auth().currentUser?.uid
if let actualUserID = userID {
Database.database().reference().child("Tracking").child(actualUserID).observe(.childAdded, with: { (snapshot) in
if let dictinaryProperty = snapshot.value as? [String: AnyObject]{
// Assign property to Property()
self.property = Property()
// set the variables in dictionaryProperty's value to property's value (Be carefull the names have to match)
self.property?.setValuesForKeys(dictinaryProperty)
// Then add it to arrayPropertys
self.arrayPropertysTracking.append(self.property!)
// This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}, withCancel: nil)
// Remove
Database.database().reference().child("Tracking").child(actualUserID).observe(.childRemoved, with: { (snapshot) in
if let dictinaryProperty = snapshot.value as? [String: AnyObject]{
// Assign property to Property()
self.property = Property()
// set the variables in dictionaryProperty's value to property's value (Be carefull the names have to match)
self.property?.setValuesForKeys(dictinaryProperty)
// Then add it to arrayPropertys
//self.arrayRemovedTracking.append(self.property!)
// Remove the property from arrayPropertysTracking
for remove in 0...self.arrayPropertysTracking.count-1 {
if self.arrayPropertysTracking[remove].keyID == self.property?.keyID {
self.arrayPropertysTracking.remove(at: remove)
return
}
}
// This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}, withCancel: nil)
}
}
Forth:
// Fetch the down button actions
func fetchActionsForDowns() {
let userID = Auth.auth().currentUser?.uid
if let actualUserID = userID {
// Add the first property
Database.database().reference().child("Actions For Downs").child(actualUserID).observe(.childAdded, with: { (snapshot) in
// The key is the property owner's ID
let keySnapshot = snapshot.key as? String
// Tags of saved buttons
let valueSnapshot = snapshot.value as? String
if let actualKey = keySnapshot {
self.arrayDownsKeyIDs.append(actualKey)
}
//This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}, withCancel: nil)
// Removed the saved actions in Firebase when a property delected in Tracking window
Database.database().reference().child("Actions For Downs").child(actualUserID).observe(.childRemoved, with: { (snapshot) in
// The key is the property owner's ID
let keySnapshot = snapshot.key as? String
// Tags of saved buttons
// let valueSnapshot = snapshot.value as? String
if let actualKey = keySnapshot {
self.arrayDownsRemoved.append(actualKey)
}
// Remove the action from the array
self.removeActionsForDownsFunctions()
// When saved is clicked twice clear the arrayRemovedTags
self.arrayDownsRemoved.removeAll()
//This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}, withCancel: nil)
}
}
Fünfte;
func fetchAnsweresOnDowns() {
let userID = Auth.auth().currentUser?.uid
if let actualUserID = userID {
Database.database().reference().child("Answers for Downs").child(actualUserID).observe(.childAdded, with: { (snapshot) in
if let dictinaryProperty = snapshot.value as? [String: AnyObject]{
// this will empty the variables in downedProperty
self.answerDowns = Property()
// set the variables in dictionaryProperty's value to property's value (Be carefull the names have to match)
self.answerDowns?.setValuesForKeys(dictinaryProperty)
// Type
self.answerDowns?.downID = snapshot.key
// Then add it to arrayPropertys
self.arrayAnswerDowns.append(self.answerDowns!)
// Do not upload unless cell has been clicked
if self.isExpanded == true {
// Upload into received downs
self.uploadeReceivedDowns(receive:self.arrayPropertys[(self.selectedIndex?.row)!])
}
// This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}, withCancel: nil)
// Removed property from answers on downs
Database.database().reference().child("Answers for Downs").child(actualUserID).observe(.childRemoved, with: { (snapshot) in
if let dictinaryProperty = snapshot.value as? [String: AnyObject]{
// this will empty the variables in downedProperty
self.answerDowns = Property()
// set the variables in dictionaryProperty's value to property's value (Be carefull the names have to match)
self.answerDowns?.setValuesForKeys(dictinaryProperty)
// Type
self.answerDowns?.downID = snapshot.key
// Then add it to arrayPropertys
self.arrayRemovedAnswerDowns.append(self.answerDowns!)
self.removeAnswerDownsFunction()
// This will crash because of background thread, so lets use DispatchQueue.main.async
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}, withCancel: nil)
}
}
Hier ist die viewDidLoad() Funktion für die Hauptansicht-Controller:
verride func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// User is not logged in
checkIfUserIsLogedin()
// The delegate for receiving an action/data and notifying the viewcontroller
// The datasource is to feed an object such as a tableview and piker from the viewcontroller
tableView.delegate = self // Notify the ViewController whenever the user tabs on rows or scroll
tableView.dataSource = self // The dataSource will ask the ViewController for table cells
// Initialize ref
ref = Database.database().reference()
// Creates UINib documents(i.e it create the the files created by main.storyboard or simailiar and truning them to a file)
let nib = UINib.init(nibName: "CustomTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cell")
// Set up the search bar
searchBarSetup()
// This function has to be here to reload table view with added property (i.e refresh table)
fetchProperties()
fetchSavedActionsForTracking()
fetchTracking()
fetchActionsForDowns()
fetchAnsweresOnDowns()
}
und hier ist, wo ich überprüfen, ob der Benutzer angemeldet ist oder nicht ist (existiert auch in den Hauptansicht-Controller):
func checkIfUserIsLogedin() {
if Auth.auth().currentUser?.uid == nil {
perform(#selector(handleLogout), with: nil, afterDelay: 0)
//handleLogout()
}
}
func handleLogout() {
// When User click logout
do {
try Auth.auth().signOut()
} catch let logoutError {
print(logoutError)
}
// Object of loginViewController
loginVC = storyboard?.instantiateViewController(withIdentifier: "LoginVC")
// Transition to loginViewController()
present(loginVC!, animated: true, completion: nil)
}
Hier ist die Authentifizierung (I es in separaten view-Controller haben)
Anmelden:
// Sign in into Firebase
func handleLogin() {
// Unwrap the text fields using guard which will simply do if-statament
guard let email = emailTextField.text, let password = passwordTextField.text else {
print("is nil")
return
}
Auth.auth().signIn(withEmail: email, password: password) { (user, err) in
if err != nil {
// There is an error
if email == "" || password == "" {
print("Empty")
// Create an alert message
let alertMessage = UIAlertController(title: "Empty Fields", message: "Please Fill The Fields", preferredStyle: .alert)
// Attach an action on alert message
alertMessage.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
alertMessage.dismiss(animated: true, completion: nil)
}))
// Display the alert message
self.present(alertMessage, animated: true, completion: nil)
return
}
print("Wrong Email or Password")
// Create an alert message
let alertMessage = UIAlertController(title: "Wrong Email or Password", message: "Please try again", preferredStyle: .alert)
// Attach an action on alert message
alertMessage.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
alertMessage.dismiss(animated: true, completion: nil)
}))
// Display the alert message
self.present(alertMessage, animated: true, completion: nil)
return
}
// Sueccessful
self.presentingViewController?.dismiss(animated: true, completion: nil)
print("Login sueccessful into Firebase database")
}
}
Registrierung:
func handleRegister() {
// Unwrap the text fields using guard which will simply do if-statament
guard let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text else {
print("is nil")
return
}
// Upload the user's name and email into authentication
Auth.auth().createUser(withEmail: email, password: password) { (user: User?, error) in
if error != nil {
// Handle the error (i.e notify the user of the error)
if email == "" || password == "" || name == "" {
print("Empty")
// Create an alert message
let alertMessage = UIAlertController(title: "Empty Fields", message: "Please Fill The Fields", preferredStyle: .alert)
// Attach an action on alert message
alertMessage.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
alertMessage.dismiss(animated: true, completion: nil)
}))
// Display the alert message
self.present(alertMessage, animated: true, completion: nil)
return
}
else if let errCode = AuthErrorCode(rawValue: error!._code) {
switch errCode {
case .invalidEmail:
print("invalid email")
// Create an alert message
let alertMessage = UIAlertController(title: "Invalid Email", message: "Please check the entered email address", preferredStyle: .alert)
// Attach an action on alert message
alertMessage.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
alertMessage.dismiss(animated: true, completion: nil)
}))
// Display the alert message
self.present(alertMessage, animated: true, completion: nil)
case .emailAlreadyInUse:
print("in use")
// Create an alert message
let alertMessage = UIAlertController(title: "Existed Email", message: "The email existed in our database, login instead of registering", preferredStyle: .alert)
// Attach an action on alert message
alertMessage.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
alertMessage.dismiss(animated: true, completion: nil)
}))
// Display the alert message
self.present(alertMessage, animated: true, completion: nil)
case .weakPassword:
print("password is weak")
// Create an alert message
let alertMessage = UIAlertController(title: "Password is weak", message: "Use upper and lower characters along with numbers", preferredStyle: .alert)
// Attach an action on alert message
alertMessage.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
alertMessage.dismiss(animated: true, completion: nil)
}))
// Display the alert message
self.present(alertMessage, animated: true, completion: nil)
default:
print("Other error!")
}
}
}
// Get the user id from Firebase
guard let uid = user?.uid else {
return
}
// Successfully authenticated
//Upload the name and user's ID into Database
let usersReference = self.ref?.child("Users Info").child(uid)
let values = ["name": name, "email": email]
//self.ref?.child("User1").setValue(values)
// Will add valuse without overwriting
usersReference?.updateChildValues(values, withCompletionBlock: { (err, ref) in
if err != nil {
print(err)
return
}
// Transition to home screen
self.presentingViewController?.dismiss(animated: true, completion: nil)
print("Saved user successfully into Firebase database")
})
}
}
Hier ist die viewDidLoad() in dem Logging-View-Controller:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// initialize the constraints of the white view and stack view
containerView.translatesAutoresizingMaskIntoConstraints = false
stackView.translatesAutoresizingMaskIntoConstraints = false
nameTextField.translatesAutoresizingMaskIntoConstraints = false
emailTextField.translatesAutoresizingMaskIntoConstraints = false
passwordTextField.translatesAutoresizingMaskIntoConstraints = false
// Create a varaible ref for Firebase
ref = Database.database().reference()
// You have to add the text field delegate if you want to add fuctions when user press/finish typing. For example when "return" key press, hide the keyboard
self.nameTextField.delegate = self
self.emailTextField.delegate = self
self.passwordTextField.delegate = self
Wann rufen Sie diese Funktionen auf und wann authentifizieren Sie den Benutzer? –
Hey Jen, ich rufe sie an, sobald der Benutzer sich anmeldet. Ich habe einen anderen View-Controller, der den Benutzer auffordert, sich anzumelden. Ich habe gerade die Authentifizierung in den Post hinzugefügt. – Ahmadiah
Danke für die Aktualisierung. Können Sie auch Ihre viewDidLoad und viewDidAppear einschließen, wenn sie Code enthalten? Weil mein erster Gedanke ist, präsentieren Sie die Anmeldung VC über die andere VC nach der ersten geladen, so dass die Listener möglicherweise registriert werden, bevor der Benutzer tatsächlich angemeldet ist. Aber das ist nur eine Vermutung, da ich den Code nicht habe. –