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)
}
}
...
Related
I changed it so that a child has multiple parameters(image and caption) instead of just being an image child.
This is what I have as relevant code.
class MyUser {
var UserFirstName: String?
var PhotoPosts: String?
init(UserFirstName: String?, Photos: String?) {
self.Photos = Photos
self.UserFirstName = UserFirstName
}
}
var peeps = [MyUser]()
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let image1 = cell.viewWithTag(1) as! UIImageView
let person: MyUser = peeps[indexPath.row]
cell.lblName.text = person.UserFirstName
if let Photos = person.Photos {
let url = URL(string: Photos)
image1.sd_setImage(with: url)
}
return cell
}
And
musicians.observe(DataEventType.value, with: {snapshot in
for peeps in snapshot.children.allObjects as! [DataSnapshot] {
if peeps.key != thisUsersUid {
let peepsObject = people.value as? [String: AnyObject]
let peepsUserFirstName = peopleObject?["UserFirstName"] as? String
let peepsPhotos = peopleObject?["Photos"] as? String
let RAA = MyUsers(Photos: peepsPhotos, UserFirstName: peepsUserFirstName)
self.peeps.append(RAA)
}
self.table.reloadData()
}
}
I'd like it to fetch the image parameter of the child and not look for the image only behind the child reference.
I am pushing data which is an array of strings to a tableview controller. These strings are "uid's" which are users in my database. With this array I make a call to firebase to extract all users and then do a match to the uid's. I am getting the correct data, yet I print out everything to make sure when the data is available and the data is available only after the tableview cell loads which causes the data to be nil causing a crash or just empty data. How can I make the data load first and then the cell so the data is available for display?
I've created functions for the data and now I have it in my viewDidLoad. Also, you'll see I have tried adding the firebase call into the Cell setup but of course that does not work.
Array of strings
var data = [String]()
viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
Database.database().reference().child("Businesses").observe(.value, with: { snapshot in
if snapshot.exists() {
self.businessUID = snapshot.value as? NSDictionary
if let dict = snapshot.value as? NSDictionary {
for item in dict {
let json = JSON(item.value)
let businessUid = json["uid"].stringValue
for uid in self.data {
if uid == businessUid {
let customerValue = self.businessUID?[uid]
self.businessDictionary = customerValue as! NSDictionary
print(self.businessDictionary)
print("Just printed the business dictionary")
}
}
}
}
} else {
print("does not exist")
}
})
}
Tableview Cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomerViewsSelectedBusinessesCell
print(self.businessDictionary)
print("Print the dictionary here to check the values")
let businessValues = self.businessDictionary
let uid = self.data.description
print(businessValues)
print("printed the business values")
if let dict = businessValues {
for item in dict {
let json = JSON(item.value)
let businessUid = json["uid"].stringValue
for uid in self.data {
if uid == businessUid {
let customerValue = self.businessUID?[uid]
self.businessData = customerValue as? NSDictionary
print(self.businessData)
print("Printing matching the uid values")
}
}
}
}
cell.businessName.text = businessData?["businessName"] as? String
cell.businessStreet.text = businessData?["businessStreet"] as? String
cell.businessCity.text = businessData?["businessCity"] as? String
cell.businessState.text = businessData?["businessState"] as? String
let businessProfilePicture = businessData?["profPicString"] as? String
if (businessProfilePicture!.characters.count) > 0 {
let url = URL(string: (businessProfilePicture!))
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
cell.profileImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.profileImage.image = image
}
}
} else {
let image = UIImage(named: "default")?.potter_circle
cell.profileImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.profileImage.image = image
}
return cell
}
Here is my solution. Got it to work. Appened and used "usersArray" to get and display the data.
var data = [String]()
var usersArray = [NSDictionary?]()
override func viewDidLoad() {
super.viewDidLoad()
Database.database().reference().child("Businesses").observe(.value, with: { snapshot in
if snapshot.exists() {
self.businessUID = snapshot.value as? NSDictionary
if let dict = snapshot.value as? NSDictionary {
for item in dict {
let json = JSON(item.value)
let businessUid = json["uid"].stringValue
for uid in self.data {
if uid == businessUid {
let customerValue = self.businessUID?[uid]
self.usersArray.append(customerValue as! NSDictionary)
self.followUsersTableView.reloadData()
}
}
}
}
} else {
print("does not exist")
}
})
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.usersArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomerViewsSelectedBusinessesCell
let user : NSDictionary?
user = self.usersArray[indexPath.row]
cell.businessName.text = String(user?["businessName"] as! String)
cell.businessStreet.text = String(user?["businessStreet"] as! String)
cell.businessCity.text = String(user?["businessCity"] as! String)
cell.businessState.text = String(user?["businessState"] as! String)
let businessProfilePicture = String(user?["profPicString"] as! String)
if (businessProfilePicture.characters.count) > 0 {
let url = URL(string: (businessProfilePicture))
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
cell.profileImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.profileImage.image = image
}
}
} else {
let image = UIImage(named: "default")?.potter_circle
cell.profileImage.contentMode = UIView.ContentMode.scaleAspectFill
cell.profileImage.image = image
}
return cell
}
I have been trying to load facebook taggable_friends, I was able to get them but can't load them in UItableView. I tried fetching request in the method "cell for Row at" but it changes the order or refresh every 2-3 seconds. I tried declaring arrays and store the names and profile pictures but I get a crash.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "friendCell", for: indexPath) as! friendstvc
// The first try
/*FBSDKGraphRequest(graphPath: "me/taggable_friends?limit=5000", parameters: nil).start { (connection, result, error) in
if error != nil
{
print(error?.localizedDescription ?? "")
cell.friendName.text = ""
return
}
let dic = result as! Dictionary<String, Any>
let data = dic["data"] as! NSArray
if let name = dic["name"]
{
print(name as! String)
}
let valuedict = data[indexPath.row] as! Dictionary<String, Any>
let id = valuedict["id"] as! String
let name = valuedict["name"] as! String
cell.friendName.text = name
cell.profpic.profileID = id
}*/
// The second try
cell.friendName.text = friendnames[indexPath.row] // crashes here
cell.profpic.image = friendpictures[indexPath.row]
return cell
}
The below method is called in the viewDidLoad for the second try
// for the second try
func loadtaggableFriends()
{
// Called in the viewDidLoad
FBSDKGraphRequest(graphPath: "me/taggable_friends?limit=5000", parameters: nil).start { (connection, result, error) in
if error != nil{
print(error?.localizedDescription ?? "")
return
}
let dic = result as! Dictionary<String, Any>
let data = dic["data"] as! NSArray
if let name = dic["name"]
{
print(name as! String)
}
print(data.count)
for i in 0...data.count - 1
{
let valuedict = data[i] as! Dictionary <String, Any>
let name = valuedict["name"] as! String
var dataurl: Data?
if let picture = valuedict["picture"] as? NSDictionary, let data = picture["data"] as? NSDictionary, let url = data["url"] as? String
{
let loadurl = URL(string: url)
dataurl = try? Data(contentsOf: loadurl!)
}
friendnames.append(name)
friendpictures.append(UIImage(data: dataurl!)!)
}
}
}
// declaring the arrays
var friendnames = [String]()
var friendpictures = [UIImage]()
Problem is that you are using two array instead of two array use one array of dictionaries like : [[String:AnyObject]] .And way of using dictionary and inserting data into array is :
let dict = [String:AnyObject]() //create dictionary
dict["friendpicture"] = "" //
dict["friendnames"] = "" //enter your data
arrOfDictionaries.append(dict) //insert data into array
Access data inside cellForRowAt method like this :
let dict = arrOfDictionaries[indexPath.item]
friendpicture = dict["friendpicture"]
friendnames = dict["friendnames"]
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 an app where users can like posts and I want to determine if the current user has previously liked a post in an efficient manner. My data currently looks like this:
I also store the likes for every user
In my current query I am doing this:
if let people = post["peopleWhoLike"] as? [String: AnyObject] {
if people[(Auth.auth().currentUser?.uid)!] != nil {
posst.userLiked = true
}
}
However, I believe this requires me to download all of the post's likes which isn't very efficient, so I tried this:
if (post["peopleWhoLike\(Auth.auth().currentUser!.uid)"] as? [String: AnyObject]) != nil {
posst.userLiked = true
}
The second method doesn't seem to be working correctly. Is there a better way to do this?
Here is my initial query as well:
pagingReference.child("posts").queryLimited(toLast: 5).observeSingleEvent(of: .value, with: { snap in
for child in snap.children {
let child = child as? DataSnapshot
if let post = child?.value as? [String: AnyObject] {
let posst = Post()
if let author = post["author"] as? String, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String, let postDescription = post["postDescription"] as? String, let timestamp = post["timestamp"] as? Double, let category = post["category"] as? String, let table = post["group"] as? String, let userID = post["userID"] as? String, let numberOfComments = post["numberOfComments"] as? Int, let region = post["region"] as? String, let numLikes = post["likes"] as? Int {
Solved it:
In the tableView I just query for the liked value directly and then determine what button to display.
static func userLiked(postID: String, cell: BetterPostCell, indexPath: IndexPath) {
// need to cache these results so we don't query more than once
if newsfeedPosts[indexPath.row].userLiked == false {
if let uid = Auth.auth().currentUser?.uid {
likeRef.child("userActivity").child(uid).child("likes").child(postID).queryOrderedByKey().observeSingleEvent(of: .value, with: { snap in
if snap.exists() {
newsfeedPosts[indexPath.row].userLiked = true
cell.helpfulButton.isHidden = true
cell.notHelpfulButton.isHidden = false
}
})
likeRef.removeAllObservers()
}
}
}
Called in my TableView:
DatabaseFunctions.userLiked(postID: newsfeedPosts[indexPath.row].postID, cell: cell, indexPath: indexPath)