IOS : message doesn't appear immediately in tableview from firebase database - ios

when i add first message it's appear immediately in the tableview but next messages don't appear i have to back and return to the same chat to get them
retrieve messages method
my database
viewDidLoad
`
func fetchMessage(key1:String){
let mydatabase = FIRDatabase.database().reference().child("message")
let query = mydatabase.queryOrderedByKey().queryEqual(toValue: key1)
query.observe(.childAdded) { (snapshot) in
for dict in snapshot.children{
let childsnap = dict as! FIRDataSnapshot
let dict2 = childsnap.value as! [String: Any]
var message = chatmssage()
let body = dict2["MesageBody"]! as? String
let email = dict2["from"]! as? String
message.body = body
message.email = email
self.chatmessagearr.append(message)
self.mytableview.reloadData()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
mytableview.delegate = self
mytableview.dataSource = self
self.tabBarController?.tabBar.isHidden = true
messageTXTF.delegate = self
mytableview.separatorStyle = .none
let curID = (user!["id"] as? String)!
let toID = self.reciever.uid!
key = (curID < toID ? curID+toID : toID+curID )
fetchMessage(key1:key!)
}

You should call self.myTableView.reloadData() from the main thread after your fetch completes. Like this,
DispatchQueue.main.async {
self.myTableView.reloadData()
}

Related

getting duplicate data while fetch messages list firebase

Hello i am creating Chat App Using Swift And Firebase i am fetching messages and populating in tableview but when i send new message then tableview dislplaying multiple entry i am useing below code for fetching messages
func fetchAllMessage(){
guard let uid = Auth.auth().currentUser?.uid else { return }
let fetchMsgGroup = Database.database().reference().child("user-messages_group_iOS").child(uid).child(self.chatID)
fetchMsgGroup.observe(.value, with: { (snapshot) in
if snapshot.exists(){
if let dictonary = snapshot.value as? [String:AnyObject]{
self.groupMessageData.removeAll()
if let userMessages = dictonary["userMessages"] as? [String:AnyObject]{
for (key, _) in userMessages{
let messagesFrtchRef = Database.database().reference().child("messages_iOS").child(key)
messagesFrtchRef.observe(.value, with: { (snapshot1) in
if snapshot1.exists(){
if let dict = snapshot1.value as? [String:AnyObject]{
let fromId = dict["fromId"] as! String
let messageUID = dict["messageUID"] as! String
let seen = dict["seen"] as! Bool
let status = dict["status"] as! String
let text = dict["text"] as! String
let timestamp = dict["timestamp"] as! Double
let told = dict["told"] as! String
let messages = GroupMessage(fromId: fromId, messageUID: messageUID, seen: seen, status: status, text: text, timestamp: timestamp, told: told)
self.groupMessageData.insert(messages, at: 0)
}
self.tblListView.reloadData()
}else{
}
}, withCancel: nil)
}
}
}
}else{
}
}, withCancel: nil)
}
i have tried everything like clearing removing also clearing observer when needed but its not work enough for me is their anyone have any solution for this then please help me
can anyone help me to solve this out

How can i fetch data and use it in viewdidload ...not inside function?

I want to print fetched data from viewDidLoad.
I don't want to print it from the custom function itself.
when I call the fetch function in viewDidLoad.It should fetch all datas.
and after that I should be able to access or print that data from viewDidLoad itself or wherever may be.
class ContactViewController: UIViewController {
#IBOutlet var lblEmail: UILabel!
#IBOutlet var lblLocation: UILabel!
#IBOutlet var mapUIView: UIView!
var email = String()
var location = String()
var lati = Double()
var long = Double()
override func viewDidLoad() {
super.viewDidLoad()
self.fetchData()
print(email)
self.lblEmail.text = self.email
}
func fetchData(){
let manager = APIManager()
manager.parsingGet(url: BaseURL.contact) { (JSON, Status) in
if Status {
let dict = JSON.dictionaryObject
let data = dict!["data"] as! [String:Any]
// let lat = data["latitude"] as! Double
// let lon = data["longitude"] as! Double
let mail = data["email"] as! String
let loc = data["location"] as! String
DispatchQueue.main.async {
self.email = mail
self.location = loc
// self.lati = lat
//self.long = lon
}
}
}
}
}
You cannot print any data that you will be getting from an API response in viewDidLoad() method as all the lines of code specified in the viewDidLoad() method will be executed back to back and will not wait for your API call to be finished.
Even if you have a fast server it will take a couple of milliseconds to hit your API and get a response. Your compiler would have executed all lines of code with the viewDidLoad() method by then.
So you might as well print the data in DispatchQueue.main.async in your fetchData() method.
You can try using callback functions. That could be a possible way of achieving what you want. Try something like this ....
override func viewDidLoad() {
super.viewDidLoad()
getData(completion:{ result in
print(email)
self.lblEmail.text = self.email
})
}
func getData(completion: (Bool)->()) {
if status{
let dict = JSON.dictionaryObject
let data = dict!["data"] as! [String:Any]
let mail = data["email"] as! String
let loc = data["location"] as! String
DispatchQueue.main.async {
self.email = mail
self.location = loc
completion(true)
}
} else {
completion(false)
}
}
parsingGet work asynchronously. The solution is pretty easy: Assign the value to the label in the completion handler of the API
override func viewDidLoad() {
super.viewDidLoad()
self.fetchData()
}
func fetchData() {
let manager = APIManager()
manager.parsingGet(url: BaseURL.contact) { (JSON, status) in
if status {
let dict = JSON.dictionaryObject
let data = dict!["data"] as! [String:Any]
// let lat = data["latitude"] as! Double
// let lon = data["longitude"] as! Double
let mail = data["email"] as! String
let loc = data["location"] as! String
self.email = mail
self.location = loc
print(mail)
DispatchQueue.main.async {
self.lblEmail.text = mail
}
}
}
}

Firebase iOS - observe value listener not working properly

var postData = [String]()
var Handle:DatabaseHandle?
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
guard let uid = Auth.auth().currentUser?.uid else {return}
let database = Database.database().reference()
Handle = database.child("Shifts").child("7 27").observe(.value) { (snapshot) in
print(snapshot)
let post = snapshot.value as? String
if let actualPost = post{
self.postData.append(actualPost)
self.tableView.reloadData()
}
}
}
I can't seem to get the data from the snapshot copied over to the postData properly. The snapshot contains the correct data. It is weird because if I changed the ".value" to ".childAdded" the code will do what it is supposed to, but I need to be looking at all of the values not just to see if something is added.
Thanks

Return from initializer without initializing all stored properties Xcode 8

I upgraded to Xcode 8 and my app stopped working and I have been able to fix everything but this one error. I have been looking online and I have not found a fix for this error. Any Help would be appreciated.
Here is the code:
struct Party {
let itemRef:FIRDatabaseReference?
//
let userID:String!
let name:String!
let title:String!
let body:String!
init (userID:String, name:String, title:String = "", body:String) {
self.userID = userID
self.name = name
self.title = title
self.body = body
self.itemRef = nil
}
init (snapshot:FIRDataSnapshot) {
userID = snapshot.key
itemRef = snapshot.ref
if let titl = snapshot.value as? [String:AnyObject] {
for child in titl{
let shotKey = snapshot.children.nextObject() as! FIRDataSnapshot
if let title = child.value as? [String:AnyObject]{
let title = title["title"]
print(title)
}
}
}else{
title = "Failed To Display Title"
}
if let user = snapshot.value as? [String:AnyObject] {
for child in user{
let shotKey = snapshot.children.nextObject() as! FIRDataSnapshot
if let name = child.value as? [String:AnyObject]{
let name = name["name"]
print(name)
}
}
}else{
name = "Failed To Display Name"
}
if let partyBody = snapshot.value as? [String:AnyObject]{
for child in partyBody{
let shotKey = snapshot.children.nextObject() as! FIRDataSnapshot
if let body = child.value as? [String:AnyObject]{
let body = body["body"]
print (body)
}
}
}else{
body = "Failed To Display Time"
}
}
func toAnyObject() -> Any {
return ["title":title, "name":name, "body":body]
}
}
Your second init(snapshot:) function doesn't set the name, title, and body properties under certain conditions.
You have this code for the title:
if let titl = snapshot.value as? [String:AnyObject] {
for child in titl{
let shotKey = snapshot.children.nextObject() as! FIRDataSnapshot
if let title = child.value as? [String:AnyObject]{
let title = title["title"]
print(title)
}
}
}else{
title = "Failed To Display Title"
}
This code only sets the title property in the else clause. The four references to title inside the if part are references to local variables named title, not the property named title. So the compiler complains you never set the title property because there is a possible code path where it isn't set.
You have the same issue for name and body.

Get data from Firebase

I am trying to get data from Firebase, I have tried like this:
FIREBASE_REF.childByAppendingPath("tasks").observeEventType(.Value, withBlock: { (snapshot) -> Void in
print(snapshot.value)
self.tasks = [Task]()
var task = Task()
let data = snapshot.value as! NSDictionary
let tasksFromServer = data.allValues as! [NSDictionary]
for taskFromServer in tasksFromServer {
task.description = taskFromServer.objectForKey("description") as! String
task.startTime = taskFromServer.objectForKey("startTime") as! String
task.endTime = taskFromServer.objectForKey("endTime") as! String
task.progress = taskFromServer.objectForKey("progress") as! Int
let priorityTemp = taskFromServer.objectForKey("priority") as! Int
switch priorityTemp {
case 0: task.priority = .Low
case 1: task.priority = .Medium
case 2: task.priority = .High
default: break
}
task.assignee = taskFromServer.objectForKey("assignee") as! String
self.tasks.append(task)
}
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
self.tableView.reloadData()
}
but it shows error in this line:
let data = snapshot.value as! NSDictionary
It says: Could not cast value of type '__NSArrayM' (0x10ebfc8d8) to 'NSDictionary' (0x10ebfcd60).
My data from Firebase like this:
But in other side, I use another code in another ViewController to get users name and role from Firebase, it works.
FIREBASE_REF.childByAppendingPath("users").observeEventType(.Value, withBlock: { (snapshot) -> Void in
self.names = []
self.roles = []
let data = snapshot.value as! NSDictionary
let employees = data.allValues as! [NSDictionary]
for employee in employees {
let name = (employee.objectForKey("firstName") as! String) + " " + (employee.objectForKey("lastName") as! String)
self.names.append(name)
let role = employee.objectForKey("position") as! String
self.roles.append(role)
}
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
self.collectionView.reloadData()
})
But why the first code always crash.
Any helps would be appreciated. Thanks.
Firebase transforms your dictionary object to an array if more than 50% of keys are between 0 and maximum key (exactly your case with one zero element).
https://www.firebase.com/docs/ios/guide/understanding-data.html#section-arrays-in-firebase

Resources