FIRDatabaseReference returns nil, UserID retrievable though - ios

I'm trying to retrieve data from my Firebase database, but I'm stuck at the database reference returning nil. However, I successfully can retrieve the UserID, so I don't think it's not properly connected to my database:
import UIKit
import Firebase
import FirebaseDatabaseUI
class LoggedInViewController: UIViewController {
var ref: FIRDatabaseReference!
let userid = FIRAuth.auth()?.currentUser?.uid
override func viewDidLoad() {
super.viewDidLoad()
UIDLabel.text = String((userid)!) // The Label shows the UID
reflabel.text = String(ref) // The Label shows "nil"
}
}
My goal is to retrieve data from the path using this method:
func getQuery() -> FIRDatabaseQuery {
let myTopPostsQuery = (ref.child("user-posts")).child(getUid()))
return myTopPostsQuery
}
But obviously this doesn't work since I'm getting an error because of the nil reference.

In viewDidLoad use FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
self.ref = FIRDatabase.database().reference()
//....
}

Related

Detach from Firestore listener

I'm using Firestore together with Swift.
I have a singleton data class UserManager. I call this from my different ViewControllers to get data to populate my tableviews. I want the tableviews to automatically update when the collections are updated so I need to use a SnapshotListener. Everything works fine but I'm not sure how to detach from the listener when the Viewcontroller is closed.
In the singleton class I have methods like this below. The method gives a list of users and will be called from several different places around my app.
I also want to give back a reference to the listener so that I can detach from it when the Viewcontroller is closed. But I can't get it working. The below solution gives compiler error.
I've been trying to look at the reference, for example here
https://firebase.google.com/docs/firestore/query-data/listen but I need to get it working when the data is loaded in a singleton class instead of directly in the Viewcontroller. What is the way to go here?
In UserManager:
func allUsers(completion:#escaping ([User], ListenerRegistration?)->Void) {
let listener = db.collection("users").addSnapshotListener { querySnapshot, error in
if let documents = querySnapshot?.documents {
var users = [User]()
for document in documents {
let user = User(snapshot: document)
users.append(user)
}
completion(users, listener)
}
}
}
In ViewController:
override func viewDidLoad() {
super.viewDidLoad()
UserManager.shared.allUsers(completion: { (users, listener) in
self.users = users
self.listener = listener
self.tableView.reloadData()
})
}
deinit {
self.listener.remove()
}
I guess the compiler error that you see is referring to the fact that you are using listener into it's own defining context.
Try this for a change:
In UserManager:
func allUsers(completion:#escaping ([User])->Void) -> ListenerRegistration? {
return db.collection("users").addSnapshotListener { querySnapshot, error in
if let documents = querySnapshot?.documents {
var users = [User]()
for document in documents {
let user = User(snapshot: document)
users.append(user)
}
completion(users)
}
}
}
In ViewController:
override func viewDidLoad() {
super.viewDidLoad()
self.listener = UserManager.shared.allUsers(completion: { (users) in
self.users = users
self.tableView.reloadData()
})
}
deinit {
self.listener.remove()
}
I think that getDocument instead of addSnapshotListener is what you are looking for.
Using this method the listener is automatically detached at the end of the request...
It will be something similar to
func allUsers(completion:#escaping ([User])->Void) {
db.collection("users").getDocument { querySnapshot, error in
if let documents = querySnapshot?.documents {
var users = [User]()
for document in documents {
let user = User(snapshot: document)
users.append(user)
}
completion(users)
}
} }

New added data in firebase database duplicate it self before pull to refresh using Swift3

Why when I'am adding new data to firebase database appears duplicated in my app , but when I pull down to make refresh its back again not duplicated , I put a Screenshot of how data appears in my project simulator .This is how data appears in my project
This is my Code.
import UIKit
import FirebaseDatabase
import SDWebImage
import FirebaseAuth
class ViewController: UIViewController , UITableViewDataSource , UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var Ref:FIRDatabaseReference?
var Handle:FIRDatabaseHandle?
var myarray = [Posts]()
var refresh = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
refresh.addTarget(self, action: #selector(ViewController.loadData), for: .valueChanged)
tableView.addSubview(refresh)
}
override func viewDidAppear(_ animated: Bool) {
loadData()
}
func loadData(){
self.myarray.removeAll()
Ref=FIRDatabase.database().reference()
Handle = Ref?.child("Posts").queryOrdered(byChild: "Des").queryEqual(toValue: "11").observe(.childAdded ,with: { (snapshot) in
if let post = snapshot.value as? [String : AnyObject]{
let img = Posts()
img.setValuesForKeys(post)
self.myarray.append(img)
print("##############################\(img)")
self.tableView.reloadData()
}
})
self.refresh.endRefreshing()
}
It appears self.refresh.endRefreshing() is being called outside the Firebase closure.
This is bad as that code will run before Firebase returns the data and reloads the tableView data.
Remember that Firebase is asynchronous and it takes time for the internet to get the data from the Firebase server to your app, so in-line code will usually execute before the code in the closure.
Also, the Handle is unneeded in this case unless you are using it elsewhere.
Ref?.child("Posts").queryOrdered(byChild: "Des").queryEqual(toValue: "11")
.observe(.childAdded ,with: { (snapshot) in
if let post = snapshot.value as? [String : AnyObject]{
let img = Posts()
img.setValuesForKeys(post)
self.myarray.append(img)
print("##############################\(img)")
self.tableView.reloadData()
}
self.refresh.endRefreshing()
})
Also, you may consider just removing the refreshing entirely as when you add an observer to a Firebase node (.childAdded) any time a child it added, your tableview will automatically refresh due to the code executed in the closure.

Getting a picture from firebase storage

I'm creating an iOS application which has many pictures on it. I therefore decided to use a database to store the pictures on and retrieve from the database. I have inputted the pictures manually through the Firebase site.
Here is the code I currently have:
import UIKit
import Firebase
class F_A_1: UIViewController {
#IBOutlet weak var imageViewer: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
let database = FIRDatabase.database().reference()
let storage = FIRStorage.storage().reference()
let animalref = FIRStorage.storage().reference().child("animal/bird.png")
animalref.dataWidthMaxSize(1*1000*1000){ (date, error) in
if error = nill {
print(data)
self.imageViewer.image = UIImage(data: data!)
} else {
print(error?.localizedDescription)
}
}
}
This is giving me an error which I cannot fix.
Thanks in advance :)
import UIKit
import Firebase
class F_A_1: UIViewController {
#IBOutlet weak var imageViewer: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
let database = FIRDatabase.database().reference()
let storage = FIRStorage.storage().reference()
let animalref = FIRStorage.storage().reference().child("animal/bird.png")
func nameThisWhatYouWant() {
animalref.data(withMaxSize: 1*1000*1000) { (data, error) in
if error == nil {
print(data)
} else {
print(error?.localizedDescription)
}
}
}
}
i have tried this but it gives a sigbart error
Well I have never worked with Firebase and don't know how to go about connecting it, but you have an issue where you are doing logic in your app.
class F_A_1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
let database = FIRDatabase.database().reference()
let storage = FIRStorage.storage().reference()
let animalref = FIRStorage.storage().reference().child("animal/bird.png")
func nameThisWhatYouWant() {
animalref.dataWidthMaxSize(1*1000*1000){ (date, error) in
if error = nill {
print(data)
self.imageViewer.image = UIImage(data: data!)
} else{
print(error?.localizedDescription)
}
}
}
}
I added a function called nameThisWhatYouWant where you should be handling your data, and sending it off to Firebase. As far as working with Firebase, go here to see how to set up Firebase by working with Cocoa Pods, then allowing you to import Firebase. As far as actually being able to send your data off, they have tons of documentation and examples to follow to read through.
You are comparing the error to nill instead of nil.
Where are you getting your error?

Retrieve child object value from Firebase iOS

I'm trying to retrieve the first name from a JSON database in Firebase. The structure of the database is as follows
users
|_Unique ID
|_firstName
|_lastName
|_userEmail
|_userID (Which I copied to the database from FirebaseAuth account creation)
I'm trying to display the firstName in a Welcome label. Here's how I have the view controller set up (Disclaimer, I'm a designer slowly learning how to work in XCode)
class HomeVC : UIViewController {
let rootRef = FIRDatabase.database().reference()
#IBOutlet weak var WelcomeLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let userID = (FIRAuth.auth()?.currentUser?.uid)!
rootRef.child("users").child(userID).observeSingleEventOfType(
.Value, withBlock: { (snapshot) in
let firstName = snapshot.value!["firstName"] as! String
self.WelcomeLabel.text = firstName
})
}
}
I keep getting an error saying that "fatal error: unexpectedly found nil while unwrapping an Optional value". Any ideas? Do I happen to have my database structured incorrectly?

PFQueryTableViewController not loading from Parse into Swift tableView

I am new to Swift and I am trying to find the current user location, and then query all nearby users and then load them into a UITableView in my storyboard. However, when I build my code, no data shows in my UITableView (Parse is my backend). I tried to research the problem and found this way of using PFQueryTableViewController:
PFQueryTableViewController in swift not loading data
However, when I do this
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
always returns an NSException error. How can I fix that problem or fix the below code to return my parse data into my table view?
import UIKit
import Parse
import ParseUI
import CoreLocation
class MasterTableViewController: PFQueryTableViewController {
var usersLocation: PFGeoPoint? {
didSet {
// This will reload the tableview when you set the users location.
// Handy if you want to keep updating it.
if (tableView != nil) {
tableView.reloadData()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
PFGeoPoint.geoPointForCurrentLocationInBackground { point, error in
if error == nil {
self.usersLocation = point
}
}
}
override func queryForTable() -> PFQuery {
var query = PFQuery(className: "User")
if let location = usersLocation {
query.whereKey("location", nearGeoPoint: location)
}
query.limit = 10
return query
}
In your queryForTable method it seems you're trying to query the User class.
From Parse docs, to query for users there is a special way of doing it:
example:
var query = PFUser.query()
query.whereKey("gender", equalTo:"female")
var girls = query.findObjects()
https://www.parse.com/docs/ios/guide#users-querying
Hopefully that helps

Resources