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
Related
I am manually entering in data into my database and the only variable not getting passed from my database is the author and I do not know where I am going wrong.
func getAllArticles(handler: #escaping (_ articles: [Article])-> ()){
var articleArray = [Article]()
REF_ARTICLES.observeSingleEvent(of: .value) { (articleMessageSnapshot) in
guard let articleMessageSnapshot = articleMessageSnapshot.children.allObjects as? [DataSnapshot] else {return}
for article in articleMessageSnapshot {
let content = article.childSnapshot(forPath: "content").value as? String ?? "no content"
let author = article.childSnapshot(forPath: "author").value as? String ?? "no author"
let twitterHandle = article.childSnapshot(forPath: "twitterHandle").value as? String ?? "none"
let articleTitle = article.childSnapshot(forPath: "articleTitle").value as? String ?? "no title"
let date = article.childSnapshot(forPath: "date").value as? String ?? "no date"
let article = Article(content: content, author: author, twitterHandle: twitterHandle, ArticleTitle: articleTitle, date: date)
articleArray.append(article)
}
handler(articleArray)
}
}
Please check out below code
var articleArray = [Article]()
//REF_ARTICLES
let ref = Database.database().reference().child(“articles”)
ref.observe(.childAdded, with: { (snapshot) in
print(snapshot)
guard let dictionary = snapshot.value as? [String : AnyObject] else {
return
}
let articleObj = Article()
articleObj.Content = dictionary["content"] as? String
articleObj.Author = dictionary["author"] as? String
articleObj.Twitterhandle = dictionary["twitterHandle"] as? String
articleObj.Title = dictionary["articleTitle"] as? String
articleObj.Date = dictionary["date"] as? String
self. articleArray.append(articleObj)
}, withCancel: nil)
}
I am also working on similar app where i am storing data to firebase and retrieving. Below approach i used to fetch the data from firebase database. Please try once.
func getAllArticles(handler: #escaping (_ articles: [Article])-> ()) {
Database.database().reference().child("Articles").observe(.childAdded, with: { (snapshot) in
print("articles = \(snapshot)")
if let dict = snapshot.value as? [String: Any] {
let article = Article()
article.articleTitle = dict["articleTitle"] as? String
article.author = dict["author"] as? String
article.twitterHandle = dict["twitterHandle"] as? String
article.date = dict["date"] as? String
article.content = dict["content"] as? String
self.articleArray.append(article)
}
handler(articleArray)
}, withCancel: nil)
}
im not sure what the underlying issue was, but i fixed it by deleting "author" from the firebase tree and then adding it back
I am currently learning Swift and I decided to make an iOS messaging app using Firebase. I am using JSQMessageViewController as my chat template and everything is working fine except for the fact that the app crashes when two users talking to each other are in the chat room at the same time. I am getting this error near the bottom of the function below: "Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"
Here is my code for observing and retrieving message data. I call this everytime the view appears:
private func observeMessages() {
messageRef = ref.child("ChatRooms").child(chatRoomId!).child("Messages")
let messageQuery = messageRef.queryLimited(toLast:25)
newMessageRefHandle = messageQuery.observe(.childAdded, with: { (snapshot) in
let messageData = snapshot.value as! Dictionary<String, AnyObject>
if let data = snapshot.value as? [String: AnyObject],
let id = data["sender_id"] as? String,
let name = data["name"] as? String,
let text = data["text"] as? String,
let time = data["time"] as? TimeInterval,
!text.isEmpty
{
if id != uid! {
let updateRead = ref.child("ChatRooms").child(self.chatRoomId!).child("Messages").child(snapshot.key)
updateRead.updateChildValues(["status":"read"])
}
if let message = JSQMessage(senderId: id, senderDisplayName: name, date: Date(timeIntervalSince1970: time), text: text)
{
self.messages.append(message)
self.finishReceivingMessage()
}
}else if let id = messageData["senderId"] as! String!,
let photoURL = messageData["photoURL"] as! String! { // 1
if let mediaItem = JSQPhotoMediaItem(maskAsOutgoing: id == self.senderId) {
self.addPhotoMessage(withId: id, key: snapshot.key, mediaItem: mediaItem)
if photoURL.hasPrefix("gs://") {
self.fetchImageDataAtURL(photoURL, forMediaItem: mediaItem, clearsPhotoMessageMapOnSuccessForKey: nil)
}
}
}else {
print("Error! Could not decode message data")
}
})
updatedMessageRefHandle = messageRef.observe(.childChanged, with: { (snapshot) in
let key = snapshot.key
//I am getting an error on this line
let messageData = snapshot.value as! Dictionary<String, String>
if let photoURL = messageData["photoURL"] as String! {
// The photo has been updated.
if let mediaItem = self.photoMessageMap[key] {
self.fetchImageDataAtURL(photoURL, forMediaItem: mediaItem, clearsPhotoMessageMapOnSuccessForKey: key)
}
}
})
}
Curious to what I might be doing wrong here. All help is appreciated!
I am working on a Forum that will have an unlimited number of topics created by users. So for performance I'd like to fetch only 20 topics or so at a time. When the user goes to the bottom of the Table View we should fetch 20 more and so on.
The problem is I am currently sorting the topics AFTER I fetch all of them from Firebase and I am having a hard time having them ordered correctly directly on Firebase BEFORE I fetch them and that's the only way I can see this working.
The topics are ordered by "last-post" which is a string on Firebase that I convert to Date and reorder after I pull from Firebase.
func fetchTopicsFromFirebase(){
guard let cat = self.currentCategory else {return}
DataService.ds.Topics_Base.child(cat.key).observe(.value, with: { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {//snapshots = all topics
self.allTopics = []
for top in snapshots{
if let dict = top.value as? Dictionary<String,AnyObject>{
guard let title = dict["title"] as? String else {continue}
guard let text = dict["text"] as? String else {continue}
guard let time = dict["time"] as? String else {continue}
guard let username = dict["username"] as? String else {continue}
let newTopic = Topic(subject: title, text: text, time: time, topicKey: top.key, username: username)
if let lastPost = dict["last-post"] as? String{
newTopic.lastPostTime = HelperMethods.convertStringToDate(myString: lastPost)
}
if let email = dict["email"] as? String{
let validEmail = HelperMethods.removeSpecialCharactersFromEmail(email: email)
DataService.ds.Users_Base.child(validEmail).observeSingleEvent(of: .value, with: {(snapshot) in
if let userDict = snapshot.value as? Dictionary<String,AnyObject>{
if let imgUrl = userDict["profile_image_url"] as? String{
newTopic.opImageUrl = imgUrl
}
self.allTopics.append(newTopic)
self.allTopics.sort { $0.lastPostTime! > $1.lastPostTime!}//lastPostTime is a Date object
if (self.allTopics.count == snapshots.count){
self.tableView.reloadData()
}
}
})
}
}
}
}
}
)
}
Thanks in advance for any help.
I'm trying to fill the collectionView with posts. I have to get the posts, then get some data for the users who posted them. For some reason it isn't working.
DataService.ds.REF_POSTS.child("\(self.loggedInUser!.uid)").queryLimitedToLast(30).observeSingleEventOfType(.Value, withBlock: { postDictionary in
if postDictionary.exists() {
if let snapshots = postDictionary.children.allObjects as? [FIRDataSnapshot] {
self.posts = [Post]()
for snap in snapshots {
if let postDict = snap.value as? NSDictionary {
for(name, value) in postDict {
let interval = postDict.objectForKey("timePosted") as! Double
let formattedDate = NSDate(timeIntervalSince1970: interval)
let timeAgo = self.getDate(formattedDate)
if name as! String == "postedBy" {
DataService.ds.REF_USERS.child(value as! String).observeSingleEventOfType(.Value, withBlock: { (userDictionary) in
let userDict = userDictionary.value as! NSDictionary
let username = userDict.objectForKey("username")!
let profileThumbUrl = userDict.objectForKey("profileThumbUrl")!
let key = snap.key
let post = Post(postKey: key, dictionary: postDict, username: username as! String, profileThumbUrl: profileThumbUrl as! String, timeAgo: timeAgo)
self.posts.append(post)
})
}
}
}
}
}
}
self.collectionView?.reloadData()
})
It works if I perform the reload() right after appending the posts, but there is some sort of memory leak. There isn't a problem in the Post class or filling the collection view, if I use dummy values. The problem is in this code that I posted. I think I have an extra loop or something can anyone help?
If you fear that reload() is the reason of the memory leak , you can use this hack:-
if name as! String == "postedBy" {
DataService.ds.REF_USERS.child(value as! String).observeSingleEventOfType(.Value, withBlock: { (userDictionary) in
let userDict = userDictionary.value as! NSDictionary
let username = userDict.objectForKey("username")!
let profileThumbUrl = userDict.objectForKey("profileThumbUrl")!
let key = snap.key
let post = Post(postKey: key, dictionary: postDict, username: username as! String, profileThumbUrl: profileThumbUrl as! String, timeAgo: timeAgo)
self.posts.append(post)
if posts.count == postDictionary.childrenCount{
self.collectionView?.reloadData()
}
})
}
Then also see this answer :- Firebase observeSingleEventOfType stays in memory
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.