Query Data from Firebase and write in UITextfield - ios

I'm trying to pull data from my firebase project and write the field value in a UITextfield. I can't seem to figure out how to query the data needed for the UITextfields from the firebase field values correctly.
Is there anyway to do this? I have only seen videos of people adding firebase documents to a tableview, not any for direct pull of a firebase value to a UITextfield.
I've tried:
Switching the constants to instance the UITextfield Outlets and optionally unwrap as text fields let username = data[USERNAME] as? UITextField ?? "anonymous"
Creating variables of the UITextfields and equal the collections array data. So something kind like... let self.username = Userdata[0] but I keep getting "expected pattern error"
I know these may not be appropriate syntax but this is the first time I've ever coded and attempted to make an app, but I can't find any tutorial to follow for this scenario. So any information greatly appreciated, Thanks.
Heres what I've got so far...
import UIKit
import FirebaseDatabase
import Firebase
class ProfileVC: UIViewController {
#IBOutlet weak var userImage: UIImageView!
#IBOutlet weak var username: UITextField!
#IBOutlet weak var firstname: UITextField!
#IBOutlet weak var userEmail: UITextField!
#IBOutlet weak var lastname: UITextField!
#IBOutlet private weak var bgView: UIView!
//variables
private var Userdatas = [Userdata]()
private var usersCollectionRef: CollectionReference!
override func viewDidLoad() {
super.viewDidLoad()
usersCollectionRef = Firestore.firestore().collection(USERS_REF)
}
override func viewWillAppear(_ animated: Bool){
usersCollectionRef.getDocuments { (snapshot, error) in
if let err = error {
debugPrint("Error fetching docs: \(err) ")
} else {
guard let snap = snapshot else{return}
for document in snap.documents {
let data = document.data()
let username = data[USERNAME] as? String ?? "anonymous"
let firstname = data[FIRST_NAME] as? String ?? "Anonymous"
let lastname = data[LAST_NAME] as? String ?? "Anonymous"
let email = data[EMAIL] as? String ?? "Anonymous"
let documentID = document.documentID
let newuserData = Userdata(username: username, email: email, firstname: firstname, lastname: lastname, documentID: documentID)
}
}
}
}

Related

How to create a new user in firebase

I have been trying to follow the docs to authenticate a new user into firebase but when my user sign up their information is not appearing in firebase authentication
So I tried turning my password/email text field into a string that might help get rid of this issue but I received this error
Cannot convert value of type 'UITextField?' to expected argument type 'String'
so I tried using
let{
But now I can't type into the text field at all to enter the user data into firebase so how do I properly set up this code to authenticate my new user data ?
import UIKit
import FirebaseAuth
class SignUpViewController: UIViewController {
#IBOutlet weak var Email: UITextField!
#IBOutlet weak var Password: UITextField!
#IBOutlet weak var Username: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let password = Password.text
let email = Email.text
Auth.auth().createUser(withEmail: email!, password: password!) { authResult, error in
if let error = error {
print("Error \(error.localizedDescription)")
return
} else {
}
Try using a different name for the variables, possibly lowercased instead of
let Password = Password.text
let Email = Email.text
use
let password = Password.text
let email = Email.text
in case the compiler is complaining and using the TextField instead of the text contained in it, or if you are using SwiftUI just pass a binging like so:
#State private var email: String = ""
#State private var password: String = ""
TextField("Email here...", text: $email)
SecureField("Password here...", text: $password)
Button {
// ... check if fields are not null
Auth.auth().createUser(withEmail: email, password: password) { res, err in
// ...
}
} label: {
Text("Create User")
}
EDIT 1:
Try this and make sure to create the right segues with right names if you are copy pasting and also that the storyboard components are correctly configured and allow write text.
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func createUser(_ sender: UIButton) {
if let email = emailTextField.text, let password =
passwordTextField.text {
// create the user with email and password
}
}

How to add data to a specific uid in Firestore Database?

I would like some help with the coding on how to store data into a specific user after the user have successfully logged in. Below are the codes for the page where user can input the details of their new readings.
import UIKit
import Firebase
import FirebaseAuth
import FirebaseFirestore
class NewBookViewController: UIViewController {
#IBOutlet weak var bookTitleTextField: UITextField!
#IBOutlet weak var bookAuthorTextField: UITextField!
#IBOutlet weak var bookSummaryTextField: UITextField!
#IBOutlet weak var ratingController: UIView!
#IBOutlet weak var newBookCancelButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
func validateFields() -> String? {
if
bookTitleTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
bookAuthorTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
bookSummaryTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
return "Please fill in all the fields."
}
return nil
}
#IBOutlet weak var newBookSaveButton: UIButton!
var ref = Firestore.firestore()
#IBAction func newBookSaveButtonTapped(_ sender: Any) {
let uid = Auth.auth().currentUser?.uid
self.ref?.child("new reading").child(uid).setValue(post)
func post() {
let bookTitleTextField = "bookTitle"
let bookAuthorTextField = "bookAuthor"
let bookSummaryTextField = "bookSummary"
let post : [String : AnyObject] = [ "bookTitle" : bookTitleTextField as AnyObject, "bookAuthor" : bookAuthorTextField as AnyObject, "bookSummary" : bookSummaryTextField as AnyObject]
}
this is the successful user sign up on cloud firestore. after the user have logged in, I wanted to add those 3 data (title, author, summary) FOR the specific user.
It looks like you're close. Right now, you aren't returning anything from post, though. I think you also mean to be getting the text values from each UITextField instead of just declaring Strings with the names of the fields.
#IBAction func newBookSaveButtonTapped(_ sender: Any) {
guard let uid = Auth.auth().currentUser?.uid else {
//handle your error here
return
}
self.ref?.child("new reading").child(uid).setValue(post())
}
func post() -> [String:String] {
return ["bookTitle" : bookTitleTextField.text ?? "",
"bookAuthor" : bookAuthorTextField.text ?? "",
"bookSummary" : bookSummaryTextField.text ?? ""]
}
You should take a much safer approach to handling the user's ID and the values of the text fields. Here, the data is only written to the database if the user is logged in and all 3 of the text fields have strings in them. I don't know what collection you intended to place this document in so I went with what you wrote but I suspect it isn't right.
class NewBookViewController: UIViewController {
private let db = Firestore.firestore()
#IBAction func newBookSaveButtonTapped(_ sender: Any) {
guard let uid = Auth.auth().currentUser?.uid,
let data = bookData() else {
return
}
db.collection("new reading").document(uid).setData(data)
}
// This returns an optional dictionary (nil when the data is incomplete).
// This is entirely optional (pun) but I suspect you don't want
// empty fields in these database documents.
func bookData() -> [String: Any]? {
guard let title = bookTitleTextField.text,
let author = bookAuthorTextField.text,
let summary = bookSummaryTextField.text else {
return nil
}
let data: [String: Any] = [
"bookTitle": title,
"bookAuthor": author,
"bookSummary": summary
]
return data
}
}

Persisting Firebase Realtime Database creates null value in snapshot

So my application was working fine; I persisted the database locally using:
Database.database().isPersistenceEnabled = true
I didn't change anything but then all of a sudden it started returning a null snapshot. When I comment out that line, everything is working fine again and the label in the interface is displayed correctly, and this value is synced correctly across multiple devices. Here is a code snippet from my viewDidLoad:
import UIKit
import Firebase
import FirebaseDatabase
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var returnedName: UILabel!
#IBOutlet weak var scannedURLTextField: UITextField!
#IBOutlet weak var reentries: UILabel!
#IBOutlet weak var visitors: UILabel!
#IBOutlet weak var ticketType: UILabel!
#IBOutlet weak var statusImage: UIImageView!
#IBOutlet weak var entryOrReentrySwitch: UISwitch!
var qrDecodedURL : String!
var ticketNumber : String!
var eventID : String!
var numberOfAttendees: String!
var urlDictionary = [String : Any]()
var attendeeRef: DatabaseReference!
var ticketRef : DatabaseReference!
var entries : DatabaseReference!
var entriesRef : DatabaseReference!
var reentriesRef : DatabaseReference!
var entriesInt : Int!
var reentriesInt : Int!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
Database.database().isPersistenceEnabled = true
attendeeRef = Database.database().reference(withPath: "attendees")
ticketRef = Database.database().reference(withPath: "tickets")
entriesRef = Database.database().reference(withPath: "entries")
reentriesRef = Database.database().reference(withPath: "reentries")
self.scannedURLTextField .becomeFirstResponder()
scannedURLTextField.inputView=UIView()//create dummy view to supress keyboard
// Incresase size of switch
entryOrReentrySwitch.transform = CGAffineTransform(scaleX: 1.5, y: 1.5);
//monitor for changes in entries
entriesRef.child("entries").observe(.value, with: { (snapshot) in
print(snapshot);
self.visitors.text = "Visitors: \(snapshot.value as! String)"
let tempValue = snapshot.value as! String
self.entriesInt = Int(tempValue)
})
//Monitor for changes in reentries
reentriesRef.child("reentries").observe(.value, with: { (snapshot) in
// print(snapshot);
self.reentries.text = "Reentries: \(snapshot.value as! String)"
})
statusImage.image = UIImage.init(named: "scanQR.png")
}
The error generated is:
Could not cast value of type 'NSNull' (0x1fb2f3270) to 'NSString' (0x1fb2fcab8).
2019-10-12 18:05:54.061687-0700 VIM Tickets[621:97014] Could not cast value of type 'NSNull' (0x1fb2f3270) to 'NSString' (0x1fb2fcab8).
It fails on the self.visitors.text = "Visitors: \(snapshot.value as! String)" in the monitor for changes in entries section. Again, everything is working fine and there is data in the snapshot when I comment out the database persistence line. I even moved it to the AppDelegate, but it has the same result.
I am at a bit of a loss as to why this is happening when persistence was working before. Any suggestions would be greatly appreciated!
When you have disk persistence enabled, the Firebase client immediately fires with the current value that it knows for the node. It sounds like in your case it thinks that value is null, so it fires with that. If you have a connection to the server, it will moments later fire with the correct value that it got from the server.
The normal approach to deal with this situation is to first check whether the snapshot exists, before processing its contents.

How to update the labels in app as soon as JSON is fetched from server? If should be real time update

I am making a cricket app. I want to update the labels in iOS from URL every time server sends me the JDON file. How should I write the URL code?
import UIKit
import Foundation
struct jsonScore : Decodable {
let comment : String
let venuDetails : String
let valueToDisplay : String
let bowlingTeam : String
let battingTeam : String
let overs : Double
let targetScore : Int
let wickets : Int
let score : Int
let striker : striker
let nonStriker : nonStriker
let strikerBowler : strikerBowler
}
struct striker : Decodable{
let name: String
let runs: String
let balls: String
let fours: String
let sixes: String
}
struct nonStriker : Decodable{
let name: String
let runs: String
let balls: String
let fours: String
let sixes: String
}
struct strikerBowler : Decodable{
let name : String
let overs : String
let maidens : String
var runs : String
let wickets : String
}
class ViewController: UIViewController {
#IBOutlet weak var Comment: UITextView!
#IBOutlet weak var VenuDetails: UILabel!
#IBOutlet weak var ValueToDisplay: UILabel!
#IBOutlet weak var battingTeam: UILabel!
#IBOutlet weak var bowlingTeam: UILabel!
#IBOutlet weak var wickets: UILabel!
#IBOutlet weak var overs: UILabel!
#IBOutlet weak var score: UILabel!
#IBOutlet weak var striker: UILabel!
#IBOutlet weak var strikerRun: UILabel!
#IBOutlet weak var nonStriker: UILabel!
#IBOutlet weak var nonStrikerRun: UILabel!
#IBOutlet weak var strikerBowlerName: UILabel!
#IBOutlet weak var strikerBowlerOver: UILabel!
var timer = Timer()
// start the timer
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(getUpdatedData), userInfo: nil, repeats: true)
}
#objc func getUpdatedData() {
let jsonUrlString = "url from server"
guard let url = URL(string : jsonUrlString ) else
{ return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
//get your updated data here and update it into the UI.
do {
let jsonscore = try JSONDecoder().decode(jsonScore.self, from: data)
self.VenuDetails.text = jsonscore.venuDetails
self.Comment.text = jsonscore.comment
self.bowlingTeam.text = jsonscore.bowlingTeam
self.battingTeam.text = jsonscore.battingTeam
self.ValueToDisplay.text = jsonscore.valueToDisplay
self.wickets.text = String(jsonscore.wickets)
self.overs.text = String(jsonscore.overs)
self.score.text = String(jsonscore.score)
self.striker.text = jsonscore.striker.name + "*"
self.strikerRun.text = jsonscore.striker.runs
self.nonStriker.text = jsonscore.nonStriker.name
self.nonStrikerRun.text = jsonscore.nonStriker.runs
self.strikerBowlerName.text = jsonscore.strikerBowler.name
self.strikerBowlerOver.text = jsonscore.strikerBowler.overs
print(jsonscore)
}catch let jsonErr{
print("Error serializing json:", jsonErr)
}
}.resume()
}
}
How to I write the code so that as soon as JSON is fetched from server it gets updated in the app? I used timer also but the labels in app are not updating after first update. I want to update the app label as soon as server sends the JSON file and the update should be repeatedly.
Please help me writing the code.
As #Rmaddy said your timer use is quiet a bad idea. You can see why in the apple's Energy Efficiency Guide for iOS Apps
Timers prevent the CPU from going to or staying in the idle state,
which increases energy usage and consumes battery power.
That kind of over use will end up draining the device battery.
You should use something more efficient like web sockets(As #the4kman suggested). By using web sockets you will need to change a little bit your approach. You should consider to change your server to notify the app instead of the app being constantly downloading data from the server.
Here are some web sockets libraries that you can use:
Starscream
Socket.io
SwiftWebSocket

Firebase Database not Uploading

I have my upload code here
import UIKit
import Firebase
class ChatViewController: UIViewController {
let chatRef = FIRDatabase.database().reference().child("chat")
let userUid = FIRAuth.auth()?.currentUser?.uid
var userName = ""
#IBOutlet weak var topBar: UINavigationItem!
#IBOutlet weak var containerView: UIView!
#IBOutlet var inputTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
topBar.title = "Chat Log Controller"
FIRDatabase.database().reference().child("users/\(userUid!)/name").observe(.value) { (snap: FIRDataSnapshot) in
self.userName = (snap.value! as! String).description
}
}
#IBAction func handleSend(_ sender: AnyObject) {
let childChatRef = chatRef.childByAutoId()
let message = inputTextField.text!
childChatRef.child("text").setValue(message)
print(inputTextField.text)
}
#IBAction func handleSendByEnter(_ sender: AnyObject) {
let childChatRef = chatRef.childByAutoId()
let message = inputTextField.text!
print(userName)
childChatRef.child("name").setValue(userName)
childChatRef.child("text").setValue(message)
print(inputTextField.text)
}
}
text is successfully uploaded But
It doesn't print userName and doesn't upload it to Firebase Database
But username is nut nil!
Try to use your observer code as,
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
}
Just take self.username = snap.value! as! String
It will solve your problem.

Resources