fetching data from firebase - swift

I am new to using firebase, I am trying to fetch data from firebase. I have childIdArray, driverIdArray which I fetch from local database. I call method getLocationFromFirebase using the driverId and dateFormatForDriverLocation(20170505) I use for loop here because I have tableView where I show Estimate time arrival(eta) after calculating the etaArray. I have obseveEventType so that I can listen changes in location of Driver. Problem is I don't get the Index [i] of of Driver whose location is changed.
var etaArray : [String] = []
var childIDArray : [String] = []
var childDriverArray : [Int] = []
var latitudeArray : [Double] = []
var longitudeArray : [Double] = []
var dateFormatForDriverLocation : String?
override func viewDidLoad() {
super.viewDidLoad()
getCurrentLocationFromFirebase()
let date = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyyMMdd"
dateFormatForDriverLocation = dateFormatter.stringFromDate(date)
}
func getCurrentLocationFromFirebase()
{
let myGroup = dispatch_group_create()
for i in 0 ..< self.childDriverArray.count {
dispatch_group_enter(myGroup)
var latitudeDriver = ""
var longitudeDriver = ""
let rootReference = FIRDatabase.database().reference()
let DriverId = String(self.childDriverArray[i])
let pickLat = String(latitudeArray[i])
let pickLong = String(longitudeArray[i])
let driverPath = rootReference.child("gogoapp_driver/\(DriverId)")
driverPath.observeEventType(.Value, withBlock: { snapshot in
if snapshot.hasChild(self.dateFormatForDriverLocation!)
{
if let childSnapshot = snapshot.childSnapshotForPath("\(self.dateFormatForDriverLocation!)") as? FIRDataSnapshot
{
let currentDateData : FIRDataSnapshot = childSnapshot
print(i)
//for getting the last value of location
let child = currentDateData.children.reverse()[0]
if let latitude = child.value!!["latitude"] as? String
{
latitudeDriver = latitude
}
if let longitude = child.value!!["longitude"] as? String
{
longitudeDriver = longitude
}
self.GoogleDistanceMatrixApi(latitudeDriver, driverLong: longitudeDriver, pickUpLat: pickLat, pickUpLong: pickLong, completion: {(success) -> Void in
if success.isEmpty
{
}
else
{
self.etaArray[i] = success
}
})
}
}
})
dispatch_group_leave(myGroup)
}
}
func GoogleDistanceMatrixApi(driverLat : String, driverLong : String, pickUpLat : String, pickUpLong : String, completion:((sucess: String) -> Void)) {
var Text = "as"
completion(sucess: TEXT!)
}

Related

How to get Firebase data as a model in swift?

I am trying to get data from firebase and use it as a model that I created.
Here is my model;
class UserData{
var nickname : String = ""
var onesignal_player_id : String = ""
var step_count : Int = 0
var total_point : Int = 0
var competitions : [String:Competition] = [String:Competition]()
}
class Competition{
var end_date : String = ""
var gift : String = ""
var id: String = ""
var name: String = ""
var users : [String:Int] = [:]
}
and this is my function;
func getFirebaseData() {
ref = Database.database().reference()
ref.child("users").child("HXXNCXf6RRS4WVO12shZ3j15BnG3").observe(.value) { (snapshot) in
if let snapshotValue = snapshot.value as? Dictionary<String,Any> {
//change userData with the snapshotValue
self.userData.nickname = snapshotValue["nickname"] as! String
self.userData.step_count = snapshotValue["step_count"] as! Int
self.userData.total_point = snapshotValue["total_point"] as! Int
self.userData.onesignal_player_id = snapshotValue["onesignal_player_id"] as! String
self.userData.competitions = snapshotValue["competitions"] as! [String:Competition]
//reload UI with userData
print(self.userData.competitions)
} else {
print("An error occured while assigning snapshotValue to userData")
}
}
}
This code gave me error like this;
Could not cast value of type '__NSDictionaryM' (0x1f47ada20) to 'StepCounterApp.Competition' (0x1004c06f0).
2021-01-02 23:05:49.985711+0300 StepCounterApp[32511:3685645] Could not cast value of type '__NSDictionaryM' (0x1f47ada20) to 'StepCounterApp.Competition' (0x1004c06f0).
but when i comment out the line included self.userData.competitions from getFirebaseData function, everything works fine.
What should I do? How can I use firebase data as a model?
Finally here is my firebase data;
The problem is in your data model. Declare your model data like this
class UserData {
var nickname : String = ""
var onesignal_player_id : String = ""
var step_count : Int = 0
var total_point : Int = 0
var competitions : Competition = Competition()
}
class Competition{
var end_date : String = ""
var gift : String = ""
var id: String = ""
var name: String = ""
var users : [String:Int] = [:]
init() {
}
init(with dictionary: [String: Any]) {
self.end_date = dictionary["end_date"] as! String
self.gift = dictionary["gift"] as! String
self.id = dictionary["id"] as! String
self.name = dictionary["name"] as! String
self.users = dictionary["users"] as! [String:Int]
}
}
And inside the getFirebaseData funcation
self.userData.competitions = Competition(with: snapshotValue["competitions"] as! [String: Any])
The problem was in my data model and with the help of Raja Kishan's data model sugestion I fixed the problem.
First I changed the model little bit;
class UserData{
var nickname : String = ""
var onesignal_player_id : String = ""
var step_count : Int = 0
var total_point : Int = 0
var competitions : [String:Competition] = [String:Competition]()
}
class Competition{
var end_date : String = ""
var gift : String = ""
var id: Int = 0
var name: String = ""
var users : [String:Int] = [:]
init() {
}
init(with dictionary: [String: Any]) {
self.end_date = dictionary["end_date"] as! String
self.gift = dictionary["gift"] as! String
self.id = dictionary["id"] as! Int
self.name = dictionary["name"] as! String
self.users = dictionary["users"] as! [String:Int]
}
}
Than I add a childSnapshot to my method so I can work directly the "competitions";
func getFirebaseData() {
ref = Database.database().reference()
ref.child("users").child("HXXNCXf6RRS4WVO12shZ3j15BnG3").observe(.value) { [self] (snapshot) in
if let snapshotValue = snapshot.value as? [String:Any] {
//change userData with the snapshotValue
self.userData.nickname = snapshotValue["nickname"] as! String
self.userData.step_count = snapshotValue["step_count"] as! Int
self.userData.total_point = snapshotValue["total_point"] as! Int
self.userData.onesignal_player_id = snapshotValue["onesignal_player_id"] as! String
//******
//This part of the coded added for to solve the problem starting from here
let childSnap = snapshot.childSnapshot(forPath: "competitions")
if let childSnapValue = childSnap.value as? [String:Any] {
childSnapValue.forEach { (element) in
self.userData.competitions.updateValue(Competition(with: element.value as! [String:Any]), forKey: element.key)
}
} else {
print("something wrong with the childSnap")
}
//to here
//******
} else {
print("An error occured while assigning snapshotValue to userData")
}
}
}

Problem fetching data from firebase by using struct file

struct UserClass {
var babyName: String!
var babyHeight: String!
var babyWeight: String!
var babyURL: String!
var uid: String!
var reference:DatabaseReference!
var key: String!
init?(snapshot: DataSnapshot?) {
guard let value = snapshot?.value as? [String:AnyObject],
let uid = value["uid"] as? String,
let babyName = value["BabyName"] as? String,
let babyURL = value["BabyURL"] as? String,
let babyHeight = value["BabyHeight"] as? String,
let babyWeight = value["BabyWeight"] as? String else {
return nil
}
self.key = snapshot?.key
self.reference = snapshot?.ref
self.uid = uid
self.babyURL = babyURL
self.babyName = babyName
self.babyHeight = babyHeight
self.babyWeight = babyWeight
}
func getuserData() -> String {
return ("BabyName = \(babyName)")
}
}
func fetchCurrentUserInfo() {
var currentUserRef = Database.database().reference().child("Users").child("\(userID)")
handler = currentUserRef.queryOrderedByKey().observe(DataEventType.value, with: { (snapshot) in
print("User data = \(snapshot.value)")
let user = UserClass(snapshot: snapshot)
print(user?.babyName)
self.babyName.text = user?.babyName
})
}
I am getting user data but not user.babyName. How can I fix this?
May be this will help you, as the db structure is not mentioned in question. but you have to iterate children one by one and then use for loop to fetch the exact data from firebase.
reference = FIRDatabase.database().reference()
reference.child("Users").queryOrderedByKey().observe(DataEventType.value, with: { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots
{
let userId = child.childSnapshot(forPath: "userID").value! as! String
print(userId)
}
}
})

How to Clear Shared Dictionary which is causing saved values not to clear even when I login with other user

How can I clear the shared dictionary on logout in which I am saving login response?
Here is the code I am doing on getting status 1.
if(status == 1)
{
DispatchQueue.main.async {
GAReusableClass.sharedInstance.hideActivityIndicator()
UserDefaults.standard.set(self.DataDict, forKey:MaindataKey)
let Dict = self.mainDict[KData] as! [String: AnyObject]
print("self.DataDict", self.DataDict)
let User_ID = Dict[KUuid]as! String
print(User_ID)
let HMACSECRETKEY = self.deviceToken + "+" + User_ID
kHMACKey = HMACSECRETKEY
let cipher:String = CryptoHelper.encrypt(input:HMACSECRETKEY)!;
print(HMACSECRETKEY)
UserDefaults.standard.setValue(cipher, forKey:HmacKey)
UserDefaults.standard.set(true, forKey: "isLogin")
GAloginUserInfo.shared.saveUserInfo(dict: Dict )
let tabar = self.storyboard?.instantiateViewController(withIdentifier: "GAtHomeTabbarViewController") as! GAtHomeTabbarViewController
self.navigationController?.pushViewController(tabar, animated: true)
}
Here is the shared dictionary which I am using to save the values of login response.
import UIKit
import Firebase
class GAloginUserInfo: NSObject {
var loginUserMobileNo : String?
var loginUserId : String?
var loginUserUuid : String?
var loginUserCountry : String?
var loginUserCountryCode : String?
var loginUserEmail : String?
var loginUserlatitude : String?
var loginUserLongitude : String?
var loginUserName : String?
var loginUserQrcode : String?
var loginUserProfilePic : String?
var isverify : String?
var loginPassword : String?
var dateOfBirth: String?
var earnedPoints:String?
var loginUserGender:String?
var loginUserFollowers:Int = 0
static let shared = GAloginUserInfo()
func saveUserInfo (dict : [String : AnyObject?] ) {
if let loginUserMobileNo = dict["mobile"] as? String {
self.loginUserMobileNo = loginUserMobileNo
}
if let loginUserId = dict["id"] as? String {
self.loginUserId = loginUserId
}
if let loginUserUuid = dict["uuid"] as? String {
self.loginUserUuid = loginUserUuid
print(loginUserUuid)
}
if let loginUserCountry = dict["country"] as? String {
self.loginUserCountry = loginUserCountry
}
if let loginUserCountryCode = dict["country_code"] as? String {
self.loginUserCountryCode = loginUserCountryCode
}
if let loginUserEmail = dict["email"] as? String {
self.loginUserEmail = loginUserEmail
}
if let loginUserProfilePic = dict["profile_pic"] as? String {
self.loginUserProfilePic = loginUserProfilePic
}
if let loginUserLongitude = dict["logitude"] as? String {
self.loginUserLongitude = loginUserLongitude
}
if let loginUserName = dict["name"] as? String {
self.loginUserName = loginUserName
}
if let loginUserQrcode = dict["qr_code"] as? String {
self.loginUserQrcode = loginUserQrcode
}
if let Password = dict["password"] as? String{
self.loginPassword = Password
}
if let dateOfBirth = dict["dob"] as? String{
self.dateOfBirth = dateOfBirth
}
if let earnedPoints = dict["points"] as? String{
let myDouble = Double(earnedPoints)
let doubleStr = String(format: "%.2f", myDouble!)
self.earnedPoints = doubleStr
}
if let loginUserGender = dict["gender"] as? String{
self.loginUserGender = loginUserGender
}
if let loginUserFollowers = dict["followersCount"] as? Int{
self.loginUserFollowers = loginUserFollowers
}
}
}
Actually, the problem is when I log out and log in again with some other user it still shows some values of the previous user. I am clearing the userdefaults on the logout function. but I don't know how to clear this type of shared dictionary.
Use removeObject(forKey:)
to remove the values stored from user defaults in Logout method
UserDefaults.standard.removeObject(forKey: MaindataKey)
UserDefaults.standard.removeObject(forKey: HmacKey)
UserDefaults.standard.set(false, forKey: "isLogin")
Create a method to remove the values from the singleton class like this
extension GAloginUserInfo {
func removeUserInfo() {
self.loginUserMobileNo = nil
self.loginUserId = nil
self.loginUserUuid = nil
self.loginUserCountry = nil
self.loginUserCountryCode = nil
self.loginUserEmail = nil
self.loginUserlatitude = nil
self.loginUserLongitude = nil
self.loginUserName = nil
self.loginUserQrcode = nil
self.loginUserProfilePic = nil
self.isverify = nil
self.loginPassword = nil
self.dateOfBirth = nil
self.earnedPoints = nil
self.loginUserGender = nil
self.loginUserFollowers = 0
}
}
and call this method in logout
GAloginUserInfo.shared.removeUserInfo()

Cannot assign value of type '[String]?' to type 'String?'

This is the var var types: [String]? and here i get this error myLabel3.text = place.types how can i adjust it? I looked to other similar questions but not find something that is the same to my problem.
import UIKit
import CoreLocation
private let geometryKey = "geometry"
private let locationKey = "location"
private let latitudeKey = "lat"
private let longitudeKey = "lng"
private let nameKey = "name"
private let openingHoursKey = "opening_hours"
private let openNowKey = "open_now"
private let vicinityKey = "vicinity"
private let typesKey = "types"
private let photosKey = "photos"
class QPlace: NSObject {
var location: CLLocationCoordinate2D?
var name: String?
var photos: [QPhoto]?
var vicinity: String?
var isOpen: Bool?
var types: [String]?
init(placeInfo:[String: Any]) {
// coordinates
if let g = placeInfo[geometryKey] as? [String:Any] {
if let l = g[locationKey] as? [String:Double] {
if let lat = l[latitudeKey], let lng = l[longitudeKey] {
location = CLLocationCoordinate2D.init(latitude: lat, longitude: lng)
}
}
}
// name
name = placeInfo[nameKey] as? String
// opening hours
if let oh = placeInfo[openingHoursKey] as? [String:Any] {
if let on = oh[openNowKey] as? Bool {
isOpen = on
}
}
// vicinity
vicinity = placeInfo[vicinityKey] as? String
// types
types = placeInfo[typesKey] as? [String]
// photos
photos = [QPhoto]()
if let ps = placeInfo[photosKey] as? [[String:Any]] {
for p in ps {
photos?.append(QPhoto.init(photoInfo: p))
}
}
}
this is place class and this is the func of my customTableViewCell where i want to add it
func update(place:QPlace) {
myLabel.text = place.getDescription()
myImage.image = nil
myLabel2.text = place.vicinity
myLabel3.text = place.types
var types: [String]? is an optional array of String; the value of myLabel3.text is an optional String, or String?.
You need to get a value out from the array or join the values in order to set your label text, eg:
myLabel3.text = place.types?.joined()

Firebase: How to put data in a child that's already created with childbyAutoID

people in my app sometimes needs to update the status of something. Now can you choose of 2 things: The so called "Rollerbank" is still there or the "Rollerbank" is removed. The users can create a data ref. The id that will be created by childbyAutoID. Now is my question how to get the right child and update some childs with a value. My post:
class Post {
let ref: DatabaseReference!
var TypeControle: String = ""
var Stad: String = ""
var Tijd: String = ""
var TijdControle: String = ""
var TijdControleniet: String = ""
var Latitude: String = ""
var Longitude: String = ""
var Extrainformatie: String = ""
var Staater: String = ""
var Staaternietmeer: String = ""
init(TypeControle: String) {
self.TypeControle = TypeControle
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(Stad: String){
self.Stad = Stad
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(Tijd: String) {
self.Tijd = Tijd
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(Latitude: String) {
self.Latitude = Latitude
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(Longitude: String) {
self.Longitude = Longitude
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(Extrainformatie: String) {
self.Extrainformatie = Extrainformatie
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(Staater: String) {
self.Staater = Staater
ref = Database.database().reference().child("Rollerbanken").child("Controletest").childByAutoId()
}
init(Staaternietmeer: String) {
self.Staaternietmeer = Staaternietmeer
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(TijdControle: String) {
self.TijdControle = TijdControle
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(TijdControleniet: String) {
self.TijdControleniet = TijdControleniet
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init() {
ref = Database.database().reference().child("Rollerbanken").childByAutoId()
}
init(snapshot: DataSnapshot)
{
ref = snapshot.ref
if let value = snapshot.value as? [String : Any] {
TypeControle = value["TypeControle"] as! String
Stad = value["Stad"] as! String
Tijd = value["Tijd"] as! String
Latitude = value["Latitude"] as! String
Longitude = value["Longitude"] as! String
Extrainformatie = value["Extrainformatie"] as! String
Staater = value["Staater"] as! String
Staaternietmeer = value["Staaternietmeer"] as! String
TijdControle = value["TijdControle"] as! String
TijdControleniet = value["TijdControleniet"] as! String
}
}
func save() {
ref.setValue(toDictionary())
}
func toDictionary() -> [String : Any]
{
return [
"TypeControle" : TypeControle,
"Stad" : Stad,
"Tijd" : Tijd,
"Latitude" : Latitude,
"Longitude" : Longitude,
"Extrainformatie" : Extrainformatie,
"Staater" : Staater,
"Staaternietmeer" : Staaternietmeer,
"TijdControle" : TijdControle,
"TijdControleniet" : TijdControleniet
]
}
}
Data for the TableViewCell:
class ControleTableViewCell: UITableViewCell {
#IBOutlet weak var storyControle: UILabel!
#IBOutlet weak var storyTijd: UILabel!
var post: Post! {
didSet {
storyControle.text = "\(post.Staaternietmeer)"
storyTijd.text = "\(post.TijdControleniet)"
storyControle.text = "\(post.Staater)"
storyTijd.text = "\(post.TijdControle)"
}
}
How my update button looks like:
#IBAction func Update(_ sender: Any) {
let alertController1 = UIAlertController(title: "Update melden" , message: "De rollerbank", preferredStyle: .alert)
// Create the actions
let RollerbankAction1 = UIAlertAction(title: "Staat er nog steeds", style: UIAlertActionStyle.default) {
UIAlertAction in
NSLog("Ja Pressed")
self.newStory.Staater = self.Staater
self.newStory.TijdControle = self.TijdControle
self.newStory.save()
}
let cancelAction1 = UIAlertAction(title: "Staat er niet meer", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let Tijd = "\(hour) : \(minutes)"
self.newStory.Staaternietmeer = self.Staaternietmeer
self.newStory.TijdControleniet = Tijd
self.newStory.save()
}
alertController1.addAction(RollerbankAction1)
alertController1.addAction(cancelAction1)
self.present(alertController1, animated: true, completion: nil)
}
This is the Structure that i use. If i run all this code, the new data will go in a other childbyAutoID and thats not what i want. It just needs to update/setvalue in the cleare space named "Staaternietmeer" and "TijdControleniet". Can anybody help me with that?
You would then need to store the Push ID somewhere so that you can reuse it later.
To generate a unique Push ID you would use :
Database.database().reference().childByAutoId()
And to store it somewhere :
let postKey = Database.database().reference().childByAutoId().key
And then, say you need a method to share a post for example, and want to add this post to multiple nodes, that's how it may look like :
func sharePost(_ postContent: String, completion: #escaping (Bool) -> ()) {
guard let currentUserId = Auth.auth().currentUser?.uid else {
completion(false)
return
}
let postKey = Database.database().reference().childByAutoId().key
let postData: [String: Any] = [ "content": "blabla",
"author": currentUserId ]
let childUpdates: [String: Any] = ["users/\(currentUserId)/posts/\(postKey)": true,
"posts/\(postKey)": postData ]
Database.database().reference().updateChildValues(childUpdates, withCompletionBlock: { (error, ref) in
guard error == nil else {
completion(false)
return
}
completion(true)
})
}
Now to access the unique Push ID later on, you would use :
Database.database().reference().observe(.childAdded, with: { (snapshot) in
// Here you get the Push ID back :
let postKey = snapshot.key
// And others things that you need :
guard let author = snapshot.childSnapshot(forPath: "author").value as? String else { return }
guard let content = snapshot.childSnapshot(forPath: "content").value as? String else { return }
// Here you store your object (Post for example) in an array, and as you can see you initialize your object using the data you got from the snapshot, including the Push ID (`postKey`) :
posts.append(Post(id: postKey, content: content, author: author))
})