I am trying to download information from a Firebase Firestore document that is then appended to an array in realtime. Everytime I add a document, delete or edit a document I would like the app to update and sync the array to match the data. I was able to retrieve the data with the following code:
database.collection("_Products").getDocuments(completion: { (snapshot, error) in
if error != nil {
print(error as Any)
}else{
for document in (snapshot?.documents)! {
let Name = document.data()["Item Name"] as! String
let Price = document.data()["Item Price"] as! String
let Number = document.data()["Item Number"] as! String
let Brand = document.data()["Item Brand"] as! String
let Quantity = document.data()["Quantity"] as! String
let Category = document.data()["Item Category"] as! String
DispatchQueue.main.async {
if instoreCheckOutArray.contains(where: {$0.Number == Number && $0.Brand == Brand}){
return
}else{
instoreCheckOutArray.append(checkOutArrayInfo(Brand: Brand, Name: Name, Number: Number, Price: Price, Quantity: Quantity, Category: Category))
self.searchForCoupon()
}
}
}
}
})
I then use the following code to run the function every second to fetch the data from the database:
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCart), userInfo: nil, repeats: true)
Running the previous code perfectly fetches me new data but I cannot get the app to update the existing array to match the database and when I remove a document from the database it stays in the array.
Thank you in advanced.
1.Declare scrollingTimer variable
var scrollingTimer = Timer()
2.Initialize scrollingTimer with your function
scrollingTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCart), userInfo: nil, repeats: true)
3.Fire the scrollingTimer(fire any where you want)
scrollingTimer.fire()
To stop the scrolling timer use the below line(Stop any where you want)
scrollingTimer.invalidate()
If any Please refer the link (DevelopersDocument)
Related
I can't seem to retrieve sent sender data without getting an error "Value of 'Any' has no subscripts".
It seems like a new error since this is the way I've always done it, and I can't find information on how to fix it.
let selector = #selector(self.updatePoint(sender:))
Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: selector,
userInfo: ["index": 3, "tempPoint": tempPoints[3]],
repeats: false)
#objc func updatePoint(sender: Timer) {
guard let index = sender.userInfo?["index"] as? Int else {return} // Error: Value of 'Any' has no subscripts
...
}
userInfo is of type Any you need to cast it first to [String:Any]
guard let info = sender.userInfo as? [String:Any],let index = info["index"] as? Int else {return}
I am new to swift Programming and FireBase,I have Implemented Chat Application,Which I stored the Message Count using sender and Receiver ID ,In receiver side getting count Perfectly,But when new count is added in FireBase I want to get that new count, for that I used timer to call a function every 10 seconds,i am getting count perfectly ,But My problem is Timer running continuously, App getting Hang and slow,After sometimes I doesn't response, can anyone suggest me how to call the function every 10 seconds or how to use timer.
Here I have tried this code,
var timer = Timer()
override func viewWillAppear(_ animated: Bool) {
MessageCountingFunction()
}
func MessageCountingFunction(){
//getting count details
keyvalue.removeAllObjects()
countarray.removeAllObjects()
let ref = FIRDatabase.database().reference()
ref.child("CountDetails").child(AuthManager.User.id.value).observeSingleEvent(of: FIRDataEventType.value, with: { (snapshot) in
if let cakeSnapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for cakes in cakeSnapshot {
print(cakes)
if let cakeDictionary = cakes.value as? Dictionary <String, Any> {
print(cakeDictionary)
let count = cakeDictionary["Count"]
let key = cakes.key as String
//your class that takes a key as String and a Dictionary
print(count as Any)
print(key)
self.keyvalue.add(key)
self.countarray.add(count!)
}
}
DispatchQueue.global().sync {
print(self.keyvalue)
print(self.countarray)
self.tableView.reloadData()
}
}
})
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.MessageCountingFunction), userInfo: nil, repeats: true)
}
}
My json data structure for new message is :-
{ "status" : "sent", "sender" : "ayush ", "timeStamp" :
1525760473513 }
we are maintaining the status key for checking new message. after reading we are updating value of status key to read and looking for sent status for new message.
var channelRef: DatabaseReference = Database.database().reference().child(FIREBASE_CONSULTATION_DBKEY)
channelRef.child("channelKey").observe(DataEventType.value, with: { (snapshot) -> Void in // 1
if let channelData = snapshot.value as? Dictionary<String, AnyObject>{ // 2
let id = snapshot.key
self.chatMessageArray.removeAll()
for (key,obj) in channelData{
if status == "Sent"{
}
}
}
}
}
So I am trying to read the children of the autoID children beneath "Recipes" below is a picture of my Firebase database and beneath that is the method that is supposed to retrieve the value of "Description" and "Name" and insert them into variables.
The error that I am currently getting when running the app is this:
Could not cast value of type '__NSCFString' (0x10ad2afb8) to 'NSDictionary' (0x10ad2bfa8).
ref = Database.database().reference()
databaseHandle = ref?.child("Recipes").observe(.childAdded) { (snapshot) in
for snap in snapshot.children
{
let recipeSnap = snap as! DataSnapshot
let recipeID = recipeSnap.key
let dict = recipeSnap.value as! [String:AnyObject]
let recipeName = dict["Name"] as! String
let recipeDescription = dict["Description"] as! String
print("key = \(recipeID) and name = \(recipeName) and description = \(recipeDescription)")
}
}
The print statement is just there for testing.
Try the following and let me know if it works now:
// SEARCHES FOR SHARING CODE IN DATABASE (ONLINE)
let parentRef = Database.database().reference().child("Recipes")
parentRef.observeSingleEvent(of: .value, with: { snapshot in
// SHOWING WHATEVER WAS RECEIVED FROM THE SERVER JUST AS A CONFIRMATION. FEEL FREE TO DELETE THIS LINE.
print(snapshot)
// PROCESSES VALUES RECEIVED FROM SERVER
if ( snapshot.value is NSNull ) {
// DATA WAS NOT FOUND
print("– – – Data was not found – – –")
} else {
// DATA WAS FOUND
for user_child in (snapshot.children) {
let user_snap = user_child as! DataSnapshot
let dict = user_snap.value as! [String: String?]
// DEFINE VARIABLES FOR LABELS
let recipeName = dict["Name"] as? String
let recipeDescription = dict["Description"] as? String
print("– – – Data for the recipe \(recipeName) with the description \(recipeDescription) was found successfully! – – –")
}
}
}
If you only want to retrieve the name and description for one specific recipe, you should change the third line to
parentRef.queryEqual(toValue:DefineWhatToSearchForHere).observeSingleEvent(of: .value, with: { snapshot in
If you constantly want to update to reflect changes, you can either call this function every x seconds using a timer and adding it to override func viewDidLoad() such as
time = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(ViewController.updateFBData), userInfo: nil, repeats: true)
after creating a function called func updateFBData() in which you do whatever you want to do to get new data (see above) and calling it in a defined timeInterval
or you can do what Attila Hegedüs in this excellent tutorial.
I am making a swift program in Xcode that pulls a list of events from a firebase database, makes a table view cell for each event, and puts the said cell in a table view. The problem lies that when I set the value of an array storing the events to whatever it pulls from the firebase, the value immediately reverts after I close the snapshot. Here is the relevant code:
struct cellData {
let Title: String
let Date: String
let Time: String
let Desc: String
var Image: UIImage?
}
classTableViewController: UITableViewController {
var ref:DatabaseReference?
var arrayOfCellData = [cellData]()
override func viewDidLoad() {
ref = Database.database().reference()
ref?.child("Events").observeSingleEvent(of: .value, with {(snapshot) in
let data = snapshot.value as! NSArray
var i = 0
while(i < data.count) {
let event = data[i] as! NSArray
if(event[0] as! String == "TRUE") {
self.arrayOfCellData.append(cellData(
Title:event[1] as! String,
Date:event[2] as! String,
Time:event[3] as! String,
Desc:event[4] as! String,
Image: nil))
print(self.arrayOfCellData[i])
}
i += 1
}
})
print(arrayOfCellData.count)
}
}
Based on this code it should print each event individually(There are two events in the database) and then it should print the total amount of events in the array. However, this is what prints in the console:
0
cellData(Title: "Event #1", Date: "9/18/17", Time: "6:30 PM", Desc: "Generic Event Description", Image: nil)
cellData(Title: "Event #2", Date: "5/15/26", Time: "12:15 PM", Desc: "Please attend this event", Image: nil)
As you can see the snapshot is running after the view didLoad method. In fact, the methods defining the table views also run prior to the snapshot, causing the call to not show any of the data.
May be this will help:
I think since observeSingleEvent is an async call , so you need to use completion handler to give the data back:
Write a function named fetchData and then use it in viewDidLoad method:(as I mentioned in usage)
func fetchData(completionHandler: #escaping ([cellData]) -> Void) {
ref = Database.database().reference()
ref?.child("Events").observeSingleEvent(of: .value, with {(snapshot) in
let data = snapshot.value as! NSArray
var i = 0
while(i < data.count) {
let event = data[i] as! NSArray
if(event[0] as! String == "TRUE") {
self.arrayOfCellData.append(cellData(
Title:event[1] as! String,
Date:event[2] as! String,
Time:event[3] as! String,
Desc:event[4] as! String,
Image: nil))
print(self.arrayOfCellData[i])
}
i += 1
}
completionHandler(self.arrayOfCellData)
})
}
Usage:
self.fetchData { fetchedArray in
print(fetchedArray)
}
To solve this I just had to reload the table views from within the block. I added the line
self.tableView.reloadData()
and the table view would reload with the new data. The 0 was printing before the other data because the block of code that pulled the firebase data was running asynchronously.
I have a timer set up and it downloads the source of a text file for a phone number. No matter what I change the text in the text file on the server to it always stays the same phone number. How can I get it to download the latest string?
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function **Countdown** with the interval of 1 seconds
timer = Timer.scheduledTimer(timeInterval: 1/5, target: self, selector: #selector(self.updateCounting), userInfo: nil, repeats: true)
}
func updateCounting()
{
view.window?.level = Int(CGShieldingWindowLevel()) + 1
if (currentNumber == "")
{
resizeSmall()
}
else{
resizeLarge()
}
// let urls = URL(string : "http://www.xxxxxxxxx.net/CallerID/" + accountID + "/phone.txt")
guard var urls = URL(string : "http://www.xxxxxxxxx.net/CallerID/" + accountID + "/phone.txt")
else {
print("Error: doesn't seem to be a valid URL")
return
}
do{
var phonenumber = try String(contentsOf: urls, encoding: .ascii)
if (phonenumber != "" && !NumberList.contains(phonenumber))
{
NumberList.append(phonenumber)
print(phonenumber)
TableView.reloadData()
urls.removeAllCachedResourceValues()
}
}catch{
}
}
It always returns the same phone number even though I constantly change it