. This function is not called so i have an empty tableview how i can fix that ? I checked it using a print and the print doesn't
appear
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : feedsviewTableViewCell = tableView.dequeueReusableCell(withIdentifier: "feedsviewTableViewCell", for:indexPath) as! feedsviewTableViewCell
print("did call")
// Configure the cell...
let post = posts[(self.posts.count-1) - indexPath .row]["text"] as! String
// let post = FIRDatabase.database().reference().child("posts").observe(.value) { (snapshot: FIRDataSnapshot) in self.posts[(self.posts.count-1) - indexPath .row]["text"] as! String
//print((snapshot.value as! String))
cell.configure(nil, post:post,name: self.loggedinuserdata!["name"] as! String)
return cell
}
.This is the viewdidload
self.loggedinuser = FIRAuth.auth()?.currentUser
self.databaseref.child("users").child(self.loggedinuser!.uid).observeSingleEvent(of: .value) {
(snapshot:FIRDataSnapshot) in
self.loggedinuserdata = snapshot.value as? NSDictionary
self.databaseref.child("posts").child(self.loggedinuser!.uid).observeSingleEvent(of: .childAdded, with: {(snapshot: FIRDataSnapshot ) in
self.posts.append(snapshot.value as! NSDictionary)
self.feeds.insertRows(at: [IndexPath(row : 0 ,section : 0)], with: UITableViewRowAnimation.automatic)
}) {(error) in
print(error.localizedDescription)
}
}
Related
I'm new in Swift, so I have tableview and I need to get index path for key from firebase.
When row is clicked, I want to open a new controller where is displaying all data for that User (written in Firebase).
Here is my code for didSelectRowAt:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedGuest = guestsList[indexPath.row]
let controller = self.storyboard?.instantiateViewController(identifier: "GuestDetail") as! GuestDetailsViewController
refGuests = Database.database().reference().child("userInfo").child(uid!).child("guests")
refGuests.observeSingleEvent(of: .value) { (snapshot) in
for snap in snapshot.children.allObjects as![DataSnapshot] {
let uid = snap.key
let guestD = snap.value as! [String:AnyObject]
let guestN = guestD["guestPhoneNumber"] as! String
print("key = \(uid) and tam = \(guestN)")
}
}
controller.guestUser = selectedGuest
self.present(controller, animated: true, completion: nil)
}
I don't know how selectedUser is related to the fetched data but basically the order of the code is wrong.
As observeSingleEvent works asynchronously you have to instantiate and present the controller inside the completion closure. I suppose you have to check in the loop if selectedUser matches one of the records
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedGuest = guestsList[indexPath.row]
refGuests = Database.database().reference().child("userInfo").child(uid!).child("guests")
refGuests.observeSingleEvent(of: .value) { (snapshot) in
for snap in snapshot.children.allObjects as![DataSnapshot] {
let uid = snap.key
let guestD = snap.value as! [String:AnyObject]
let guestN = guestD["guestPhoneNumber"] as! String
print("key = \(uid) and tam = \(guestN)")
}
let controller = self.storyboard?.instantiateViewController(identifier: "GuestDetail") as! GuestDetailsViewController
controller.guestUser = selectedGuest
self.present(controller, animated: true, completion: nil)
}
}
I am trying to program a social media app and I want the posts to appear in the cells. The only things in the cell are a label for the post and a label for the topic. When I run the code there are no errors but the cells are not showing in the table. I cannot seem to figure out the problem. Thank you for your guys help.
import UIKit
import Firebase
import FirebaseDatabase
import FirebaseStorage
import FirebaseAuth
import SwiftKeychainWrapper
class FeedVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var postBtn: UIButton!
#IBOutlet var tableView: UITableView!
var posts = [Post]()
var post: Post!
var userName: String!
var refPosts: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
//getting a reference to the node posts
refPosts = Database.database().reference().child("posts")
//observing the data changes
refPosts.observe(DataEventType.value, with: { (snapshot) in
//if the reference have some values
if snapshot.childrenCount > 0 {
//clearing the list
self.posts.removeAll()
//iterating through all the values
for data in snapshot.children.allObjects as! [DataSnapshot] {
//getting values
let postObject = data.value as? [String: AnyObject]
let id = postObject?["id"]
let thought = postObject?["thought"]
let likes = postObject?["likes"]
//creating artist object with model and fetched values
let post = Post(_id: id as! String, _thought: thought as! String?, _likes: likes as! Int?)
//appending it to list
self.posts.append(post)
}
//reloading the tableview
self.tableView.reloadData()
}
})
/*refPosts.observe(.value, with: {(snapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] { //all objects in snapshot
self.posts.removeAll()
for data in snapshot {
print(data)
if let postDict = data.value as? Dictionary<String, AnyObject>{
let key = data.key
let post = Post(postKey: key, postData: postDict)
self.posts.append(post)
}
}
}
self.tableView.reloadData()
})*/
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = posts[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell{
cell.configCell(post: post)
return cell
}else{
return PostCell()
}
}
func PostToFirebase(imgUrl: String){
let userID = Auth.auth().currentUser?.uid
Database.database().reference().child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
if let data = snapshot.value as? Dictionary<String, AnyObject>{
//if let snap = snapshot.value as? [String:Any] {
let data = snapshot.value as! Dictionary<String, AnyObject>
let username = data["username"]
let post: Dictionary<String, AnyObject> = [
"username": username as AnyObject,
"likes": 0 as AnyObject
]
let firebasePost = Database.database().reference().child("posts").childByAutoId()
firebasePost.setValue(post)
self.tableView.reloadData()
}
})
}
#IBAction func postImageTapped(_ sender: AnyObject){//leads to text field box -> What are you thinking?
//present(imagePicker, animated: true, completion: nil)
//performSegue(withIdentifier: "UploadPage", sender: nil)
}
#IBAction func SignOut (_ sender: AnyObject){
try! Auth.auth().signOut()
KeychainWrapper.standard.removeObject(forKey: "uid")
dismiss(animated: true, completion: nil)
}
}
As #vadian mentioned in the comments, forcing the cast would be fine in this scenario considering you have everything setup correctly. Try adding the print statements I have below so you can see in more detail what it happening with the cells.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = posts[indexPath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell {
print("dequeueing cell")
cell.configCell(post: post)
return cell
}else{
print("initialising cell")
return PostCell()
}
}
The solution involves using the newer dequeue method that takes an index path and forcing the cast.
let post = posts[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostCell
cell.configCell(post: post)
return cell
I have a table View full of appended messages with the logged in user and other users of the app. When I swipe a cell, I want to be able to delete it from Firebase and also automatically from the tableView. I managed to get the cell deleted from Firebase but not from the tableView. This is how the messages are initially loaded into the tableView:
func loadData()
{
guard let uid = FIRAuth.auth()?.currentUser?.uid else {
return
}
FIRDatabase.database().reference().child("messages").observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
if let postsDictionary = snapshot .value as? [String: AnyObject] {
for post in postsDictionary {
let messages = post.value as! [String: AnyObject]
for (id, value) in messages {
let info = value as! [String: AnyObject]
let convoId = info["convoId"]
let toId = info["ReceiverId"] as! String!
let fromId = info["senderId"] as! String!
if (toId == self.loggedInUserUid || fromId == self.loggedInUserUid) {
let refs = FIRDatabase.database().reference().child("user-messages").child(convoId as! String).child(uid)
refs.observe(.childAdded, with: { (snapshot) in
self.messageId = snapshot.key
let ref = FIRDatabase.database().reference().child("messages").child(convoId as! String).child(self.messageId!)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let message = Message(dictionary: dictionary)
if let receiver = message.convoId {
self.messagesDictionary[receiver] = message
self.messages = Array(self.messagesDictionary.values)
print(self.messages)
self.messages.sort(by: { (message1, message2) -> Bool in
return (message1.timestamp?.int32Value)! > (message2.timestamp?.int32Value)!
})
}
//this will crash because of background thread, so lets call this on dispatch_async main thread
DispatchQueue.main.async(execute: {
self.MessageTableView.reloadData()
})
}
}, withCancel: nil) })}
}
}}})
}
Here is how I perform the delete function in Firebase and attempt to perform a delete function in the tableView:
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
guard let uid = FIRAuth.auth()?.currentUser?.uid else {
return
}
let message = messages[(indexPath.row)]
self.deletemessage = message.convoId
FIRDatabase.database().reference().child("messages").observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
if let postsDictionary = snapshot .value as? [String: AnyObject] {
for post in postsDictionary {
let messages = post.value as! [String: AnyObject]
for (id, value) in messages {
let info = value as! [String: AnyObject]
let convoId = info["convoId"]
let ref = FIRDatabase.database().reference().child("user-messages").child(self.deletemessage!).child(uid)
ref.observe(.childAdded, with: { (snapshot) in
self.messageId = snapshot.key
FIRDatabase.database().reference().child("user-messages").child(self.deletemessage!).child(uid).child( self.messageId!).removeValue(completionBlock: { (error, ref) in
if error != nil {
print("error \(error)")
}else{
}})})}}}})
self.messages.remove(at: indexPath.row)
self.MessageTableView.deleteRows(at: [indexPath], with: .automatic)
}
}
it deletes from the tableView but crashes and gives me an error on self.messages.remove(at: indexPath.row) fatal error: Index out of Range.
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let state = id[indexPath.row] //it store the child key to be removed. here id array is not displayed but used as backend process
print(state) // (Not required)
names.remove(at: indexPath.row) //Remove the selected name from array used in TableView that is displayed in cell
tableView.deleteRows(at: [indexPath], with: .fade) // TableView Animation
Database.database().reference().child("artists").child(id[indexPath.row]).removeValue() // remove the child referred using id from database
id.remove(at: indexPath.row) // removing selected if from id array locally
}
}
Try the following code In your case please and let me know issue still Exists
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
guard let uid = FIRAuth.auth()?.currentUser?.uid else {
return
}
let message = messages[(indexPath.row)]
self.deletemessage = message.convoId
FIRDatabase.database().reference().child("messages").observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
if let postsDictionary = snapshot .value as? [String: AnyObject] {
for post in postsDictionary {
let messages = post.value as! [String: AnyObject]
for (id, value) in messages {
let info = value as! [String: AnyObject]
let convoId = info["convoId"]
let ref = FIRDatabase.database().reference().child("user-messages").child(self.deletemessage!).child(uid)
ref.observe(.childAdded, with: { (snapshot) in
self.messageId = snapshot.key
FIRDatabase.database().reference().child("user-messages").child(self.deletemessage!).child(uid).child( self.messageId!).removeValue(completionBlock: { (error, ref) in
if error != nil {
print("error \(error)")
}
})
})
}
}}})
self.messages.remove(at: indexPath.row)
self.MessageTableView.deleteRows(at: [indexPath], with: .automatic)
}
}
Try this it occur because you are deleting value correct but under a handler which even caused a error in my project . data in messages is loaded from database so if value is not delete from database it will update again even if u remove from array. so please try this code
I have a firebase database reference
FIRDatabase.database().reference().child("messages").child("\(self.convoId!)").childByAutoId()
I want to access the ReceiverName from my firebase database in DisplayViewController, but when I call the database reference, I get an error because of convoId. This is how convoId was declared (in MessagesViewController).
override func viewDidLoad() {
super.viewDidLoad()
let receiverId = receiverData as! String
let receiverIdFive = String(receiverId.characters.prefix(5))
let senderIdFive = String(senderId.characters.prefix(5))
if (senderIdFive > receiverIdFive)
{
self.convoId = senderIdFive + receiverIdFive
}
else
{
self.convoId = receiverIdFive + senderIdFive
}
}
receiverData was passed from UserviewController to MessagesViewController and "senderId" is the string identifier that uniquely identifies the current user sending messages and is automatically declared in JSQMessagesViewController.h. so essentially, I can't redeclare convoId in my DisplayViewController. However, in DisplayViewController, I need to access ReceiverName.
This is how I attempted to retrieve ReceiverName:
let rootRef = FIRDatabase.database().reference()
rootRef.child("messages").observeSingleEvent(of: .value) {
(snapshot: FIRDataSnapshot) in
let loggedInUserData = snapshot
if let postsDictionary = snapshot .value as? [String: AnyObject] {
for post in postsDictionary {
self.messages.add(post.value)
}
self.MessageTableView.reloadData()
}
}
Then I populate the derived data in a tableviewcell:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath) as! MessageTableViewCell
//Configure the cell
print(messages[indexPath.row])
let message = self.messages[indexPath.row] as! [String: AnyObject]
cell.SellerName.text = message["ReceiverName"] as? String
return cell
}
Try this inside your observeSingleEvent function:
...
for post in postsDictionary {
let messages = post.value as! [String: AnyObject]
for (id, value) in messages {
let info = value as! [String: AnyObject]
let receiver = info["ReceiverName"]!
print("\(id): \(receiver)")
self.messages.add(value)
}
}
...
I´m building a widget for iOS with Swift. The main app´s purpose is to connect to a URL news feed and get the latest news, while the widget only get the title to display in a tableView in the Today view.
I´ve written this method for the widget in order to get the data to populate the table, but for some reason nothing is showing. I´ve tried to debug it, but being a widget it seems to be practically imposible.
This is the cellForRowAt, where I connect to the feed and try to extract data. The funny part is, the main app uses basically the same code and it works perfectly.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let urlRequest = URLRequest(url: URL(string: "https://newsapi.org/v1/articles?source=techcrunch&sortBy=top&apiKey=c64849bc30eb484fb820b80a136c9b0a")!)
let task = URLSession.shared.dataTask(with: urlRequest) { (data,response,error) in
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let articlesFromJson = json["articles"] as? [[String: AnyObject]] {
if !(error != nil) {
var resultArray: NSMutableArray = NSMutableArray()
for articlesFromJson in articlesFromJson {
if let title = articlesFromJson["title"] as? String{
resultArray.add(title)
}
let array:NSArray = resultArray.reverseObjectEnumerator().allObjects as NSArray
resultArray = array as! NSMutableArray
let title:String = resultArray.object(at: indexPath.row) as! String
cell.textLabel?.text = title
}
}
}
//reload on main thread to speed it up
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch let error {
print(error)
}
}
task.resume()
return cell
}
If someone can help me figure out where is the mistake it would be a huge help, i´ve been stuck on this issue for days now. Thanks
You want to make your network request outside of cellForRow and then reloadData once it's complete to have the tableView reload the cells which calls cellForRow.
store the array of data outside of request so you can reference it from outside the function.
var resultArray: NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
getData()
}
func getData() {
let urlRequest = URLRequest(url: URL(string: "https://newsapi.org/v1/articles?source=techcrunch&sortBy=top&apiKey=c64849bc30eb484fb820b80a136c9b0a")!)
let task = URLSession.shared.dataTask(with: urlRequest) {[weak self] (data,response,error) in
guard let strongSelf = self else { return }
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let articlesFromJson = json["articles"] as? [[String: AnyObject]] {
if error == nil {
for articlesFromJson in articlesFromJson {
if let title = articlesFromJson["title"] as? String{
strongSelf.resultArray.add(title)
}
let array:NSArray = strongSelf.resultArray.reverseObjectEnumerator().allObjects as NSArray
strongSelf.resultArray = array as! NSMutableArray
DispatchQueue.main.async {
strongSelf.tableView.reloadData()
}
} catch let error {
print(error)
}
}
task.resume()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let title:String = resultArray.object(at: indexPath.row) as! String
cell.textLabel?.text = title
return cell
}
checks proper if TableView delegate or datasource proper connected. and check array count before load data in cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
if (resultArray.count > 0){
let title:String = resultArray.object(at: indexPath.row) as! String
cell.textLabel?.text = title
}
else
{
print("Error: resultArray contain nil value ")
}
return cell
}