How to connect to new viewController with data saved in struct model of other viewController - swift

How can I get the data that in Struct model in new viewController
I got a viewController when i print the var in Struct model it appeare just fine.
I created New viewController trying to get the same data in otherview of that struct model but when i print it it give me nil
I tryied to make the model equal to the new model in the new viewController
MessageController View
var messages = [Message]()
var users = [Contact]()
var messagesDicionary = [String: Message]()
var testMSG : Message?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let message = self.messages[indexPath.row]
let chatPartnerId = message.chatPartnerId()
let ref = Database.database().reference().child("users").child(chatPartnerId)
ref.observe(.value) { (snap) in
if let dictinoary = snap.value as? [String: AnyObject] {
guard let email = dictinoary["email"] ,let profileimage = dictinoary["profileimage"], let userid = dictinoary["userid"], let username = dictinoary["username"] else {
return
}
var user = Contact()
user.userid = chatPartnerId
user.userid = chatPartnerId
let userValue = Contact.init(email: email as? String, username: username as? String, profileimage: profileimage as? String, userid: userid as? String)
self.users.append(userValue)
self.showChatControllerToUser(user: userValue)
print(message.receivername)
}
}
}
result of Print Optional("Omar")
ChatMessagesController View
var user :Contact?
var users = [Contact]()
var message: Message?
var messagesArray = [Message]()
func observeChatMessages() {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let userMessagesRef = Database.database().reference().child("usersmesssages").child(uid)
userMessagesRef.observe(.childAdded) { (snap) in
let messageId = snap.key
let messageRef = Database.database().reference().child("messages").child(messageId)
messageRef.observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String:AnyObject] else {
return
}
let text = dictionary["text"] as? String
let receiverid = dictionary["receiverid"] as? String
let senderid = dictionary["senderid"] as? String
let time = dictionary["timestamp"] as? TimeInterval
let senderName = dictionary["sendername"] as? String
let receiverName = dictionary["receivername"] as? String
self.messagesArray.append(MessageValue)
self.chatTableView.reloadData()
print(self.message?.receivername)
})
}
}
result of print NIL
Message Model
struct Message {
var text: String?
var receiverid: String?
var senderid: String?
var timestamp: TimeInterval?
var sendername: String?
var receivername: String?
func chatPartnerId() -> String {
return (senderid == Auth.auth().currentUser?.uid ? receiverid : senderid)!
}
}
I tried to make in MessagesController
let chatMessage = ChatMessageController()
chatMessage.message = self.testMSG

Related

Sorting cells instead of table

My App checks which POI/ Feed/ Group the user is following. Based on that it loads comments with the content of the comment and the user name/picture. Those are loaded separately. My only issue is sorting by time.
If I use this code: self.table = self.table.sorted(by: { $0.userTime ?? 0 > $1.userTime ?? 0 }) the sorting of the comments is correct. But the matching of the profile names and pictures is totally wrong.
If I remove that code above the matching is correct but the sorting is totally wrong. How can I solve this? Instead of sorting the table I have to sort the cell itself?
func loadFollowedPoi() {
myFeed.myArray1 = []
let userID = Auth.auth().currentUser!.uid
let database = Database.database().reference()
database.child("user/\(userID)/abonniertePoi/").observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children.allObjects as! [DataSnapshot] {
myFeed.myArray1.append(child.key)
}
self.postsLaden()
})
}
func postsLaden() {
dic = [:]
let neueArray: [String] = []
for groupId in myFeed.myArray1[0..<myFeed.myArray1.count] {
let placeIdFromSearch = ViewController.placeidUebertragen
ref = Database.database().reference().child("placeID/\(groupId)")
ref.observe(DataEventType.childAdded, with: { snapshot in
guard let dic = snapshot.value as? [String: Any] else { return }
let newPost = importPosts(dictionary: dic, key: snapshot.key)
guard let userUid = newPost.userID else { return }
self.fetchUser(uid: userUid, completed: {
self.table.insert(newPost, at: 0)
self.table = self.table.sorted(by: { $0.userTime ?? 0 > $1.userTime ?? 0 })
self.tableView.reloadData()
})
}
)}
}
func fetchUser(uid: String, completed: #escaping () -> Void) {
ref = Database.database().reference().child("user").child(uid).child("userInformation")
ref.observe(.value) { (snapshot) in
guard let dic = snapshot.value as? [String: Any] else { return }
let newUser = UserModel(dictionary: dic)
self.users.insert(newUser, at: 0)
completed()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.layoutMargins = UIEdgeInsets.zero
cell.post = table[indexPath.row]
cell.user = users[indexPath.row]
return cell
}
class importPosts {
var userID: String?
var userGroup: String?
var userComment: String?
var userTime: Int?
var userLikes: Int?
var commentId: String?
var placeID: String?
var kommentarCount: Int?
var id: String?
var likeCount: Int?
var likes: Dictionary<String, Any>?
var isLiked: Bool?
init(dictionary: [String: Any], key: String) {
userID = dictionary["userID"] as? String
userComment = dictionary["userComment"] as? String
userGroup = dictionary["userGroup"] as? String
userTime = dictionary["userTime"] as? Int
userLikes = dictionary["userLikes"] as? Int
commentId = dictionary["commentId"] as? String
placeID = dictionary["placeID"] as? String
kommentarCount = dictionary["kommentarCount"] as? Int
id = key
likeCount = dictionary["likeCount"] as? Int
likes = dictionary["likes"] as? Dictionary<String, Any>
ViewComments.commentIDNew = commentId!
if let currentUserUid = Auth.auth().currentUser?.uid {
if let likes = self.likes {
isLiked = likes[currentUserUid] != nil
}
}
}
}
As suggested in the comments create a parent struct which contains one user an one post respectively
struct UserData {
let user: UserModel
let post: importPosts
}
Side note: Please name structs/classes always uppercase and why not simply User and Post?
Create the datasource array
var users = [UserData]()
Modify fetchUser to pass the new user in the completion handler
func fetchUser(uid: String, completed: #escaping (UserModel) -> Void) {
ref = Database.database().reference().child("user").child(uid).child("userInformation")
ref.observe(.value) { (snapshot) in
guard let dic = snapshot.value as? [String: Any] else { return }
let newUser = UserModel(dictionary: dic)
completed(newUser)
}
}
And modify also postsLaden to assign the post and the associated user to the model
func postsLaden() {
//dic = [:]
//let neueArray: [String] = [] seems to be unused
for groupId in myFeed.myArray1[0..<myFeed.myArray1.count] {
let placeIdFromSearch = ViewController.placeidUebertragen
ref = Database.database().reference().child("placeID/\(groupId)")
ref.observe(DataEventType.childAdded, with: { snapshot in
guard let dic = snapshot.value as? [String: Any] else { return }
let newPost = importPosts(dictionary: dic, key: snapshot.key)
guard let userUid = newPost.userID else { return }
self.fetchUser(uid: userUid, completed: { user in
self.users.insert(UserData(user: user, post: newPost), at: 0)
self.users.sort($0.user.userTime ?? 0 > $1.user.userTime ?? 0)
self.tableView.reloadData()
})
}
)}
}
Finally modify cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.layoutMargins = UIEdgeInsets.zero
let user = users[indexPath.row]
cell.post = user.post
cell.user = user.user
return cell
}
Yet another side note: Sorting and reloading the table view multiple times inside the loop is unnecessarily expensive. You could add DispatchGroup to sort and reload the data once on completion. Regarding expensive: In the database isn't it possible that Post can hold a full reference to the user to avoid the second fetch? For example Core Data can.

Problem fetching data from firebase by using struct file

struct UserClass {
var babyName: String!
var babyHeight: String!
var babyWeight: String!
var babyURL: String!
var uid: String!
var reference:DatabaseReference!
var key: String!
init?(snapshot: DataSnapshot?) {
guard let value = snapshot?.value as? [String:AnyObject],
let uid = value["uid"] as? String,
let babyName = value["BabyName"] as? String,
let babyURL = value["BabyURL"] as? String,
let babyHeight = value["BabyHeight"] as? String,
let babyWeight = value["BabyWeight"] as? String else {
return nil
}
self.key = snapshot?.key
self.reference = snapshot?.ref
self.uid = uid
self.babyURL = babyURL
self.babyName = babyName
self.babyHeight = babyHeight
self.babyWeight = babyWeight
}
func getuserData() -> String {
return ("BabyName = \(babyName)")
}
}
func fetchCurrentUserInfo() {
var currentUserRef = Database.database().reference().child("Users").child("\(userID)")
handler = currentUserRef.queryOrderedByKey().observe(DataEventType.value, with: { (snapshot) in
print("User data = \(snapshot.value)")
let user = UserClass(snapshot: snapshot)
print(user?.babyName)
self.babyName.text = user?.babyName
})
}
I am getting user data but not user.babyName. How can I fix this?
May be this will help you, as the db structure is not mentioned in question. but you have to iterate children one by one and then use for loop to fetch the exact data from firebase.
reference = FIRDatabase.database().reference()
reference.child("Users").queryOrderedByKey().observe(DataEventType.value, with: { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots
{
let userId = child.childSnapshot(forPath: "userID").value! as! String
print(userId)
}
}
})

Posts Being Uploaded Randomly in Collection View - Swift & Firebase

I have been refactoring my code and now I'm having trouble with the posts.
Whenever I add a new post to the collection view, it is being added in a random cell and out of order, instead of in the first post.
I know the reason is the fetchuser function and from what I'm being told due to the asynchronous loading, but don't know what to do in order to correct this.
Could someone help me figure out what to do so that my posts are added in the first cell?
#objc func observePostsAdoption() {
let postsRef = Database.database().reference().child("posts")
postsRef.queryOrdered(byChild: "postType").queryEqual(toValue: "adopt").observe(.value) { (snapshot) in
var tempPost = [Posts]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot {
let dict = childSnapshot.value as? [String: Any]
let newAdoptiondPost = Posts.transformPost(dict: dict!)
//This will look up all users at once
self.fetchUser(userid: newAdoptiondPost.userid!, completed: {
tempPost.insert(newAdoptiondPost, at: 0)
DispatchQueue.main.async {
self.postsadoption = tempPost
self.adoptionCollectionView.reloadData()
self.refresherAdoption.endRefreshing()
}
})
}
}
}
}
func fetchUser(userid: String, completed: #escaping ()-> Void ) {
Database.database().reference().child("users").child(userid).observeSingleEvent(of: .value) { (snapshot) in
if let dict = snapshot.value as? [String: Any] {
let user = UserProfile.transformUser(dict: dict)
self.users.insert(user, at: 0)
completed()
}
}
}
Here's my Post Struct
class Posts {
//UserView
var uid: String?
var author: UserProfile?
var timestamp: Date?
var userid: String?
func getDateFormattedString() -> String {
let formatter = DateFormatter()
formatter.dateFormat = "MMM d, HH:mm"
return formatter.string(from: self.timestamp!)
}
//Image
var photoUrl: URL?
//PostInformation View
var city: String?
var municipality: String?
var name: String?
var breed : String?
var phone : String?
var address : String?
var petType: String?
var genderType: String?
var comments: String?
}
extension Posts {
static func transformPost(dict: [String: Any]) -> Posts {
let post = Posts()
//Post Picture
let photoUrl = dict["photoUrl"] as? String
post.photoUrl = URL(string: photoUrl!)
//INFO POSTS
post.userid = dict["userid"] as? String
post.city = dict["city"] as? String
post.municipality = dict["municipality"] as? String
post.name = dict["name"] as? String
post.breed = dict["breed"] as? String
post.phone = dict["phone"] as? String
post.address = dict["address"] as? String
post.comments = dict["comments"] as? String
post.petType = dict["petType"] as? String
post.genderType = dict["gender"] as? String
let timestamp = dict["timestamp"] as? Double
post.timestamp = Date(timeIntervalSince1970: timestamp!/1000)
return post
}
}
If you already have the posts ordered by post type you can just do sorting depending on the timestamp. For example
#objc func observePostsAdoption() {
let postsRef = Database.database().reference().child("posts")
postsRef.queryOrdered(byChild: "postType").queryEqual(toValue: "adopt").observe(.value) { (snapshot) in
var tempPost = [Posts]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot {
let dict = childSnapshot.value as? [String: Any]
let newAdoptiondPost = Posts.transformPost(dict: dict!)
//This will look up all users at once
self.fetchUser(userid: newAdoptiondPost.userid!, completed: {
tempPost.insert(newAdoptiondPost, at: 0)
DispatchQueue.main.async {
self.postsadoption = tempPost
self.postsadoption.sort { (p1, p2) -> Bool in
return p1.timeStamp?.compare(p2.timeStamp!) == .orderdDescending
}
self.adoptionCollectionView.reloadData()
self.refresherAdoption.endRefreshing()
}
})
}
}
}
}
With that the posts adoption array will be sorted depending on the timestamp that you have.

Code only retrieving one value from data in Firebase

As the title suggests, I'm trying to retrieve some data from firebase database, but my code's not working. I have three children (I guess that's how you call them) inside "Posts" called "title", "description" and "username" and I'm trying to get all of them and append them into a variable to use them later, but it only retrieves the first value of each of them, despite the fact that there are like 5 values. Anyone knows why?
By the way, I'm calling upon this function on my ViewDidLoad.
let postDB = Database.database().reference().child("Posts")
postDB.queryOrderedByKey().observeSingleEvent(of: .value) { (snapshot) in
if let snapshotValue = snapshot.value as? NSDictionary {
let postTitle = snapshotValue["title"] as? String
let postUsername = snapshotValue["username"] as? String
let postDesc = snapshotValue["description"] as? String
let postArray = postStruct(title: postTitle, description: postDesc, username: postUsername)
self.newPost.insert(postArray, at: 0)
}
import UIKit
import FirebaseDatabase
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// MARK: - variables
var postDB: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
// getting a node from database //
postDB = Database.database().reference().child("Posts")
// observing data changes //
postDB.observe(DataEventType.value) { (dataSnapshot) in
self.postArray.removeAll()
if dataSnapshot.childrenCount > 0 {
for post in dataSnapshot.children.allObjects as! [DataSnapshot] {
let object = post.value as! [String: Any]
let description = object["description"] as! String
let title = object["title"] as! String
let userName = object["username"] as! String
let model = postStruct(title: title, description: description, username: userName))
self.postArray.append(model)
}
}
self.tableView.reloadData()
}
}
}
Try this – the code replaces what you currently have in the snapshot handler.
if let firebaseList = snapshot.children.allObjects as? [FIRDataSnapshot] {
if let swiftList = snapshot.value as? [String:AnyObject] {
for firebaseItem in firebaseList {
let childID = firebaseItem.key as String
let swiftItem = swiftList[childID]
let postTitle = swiftItem?["title"] as? String
let postUsername = swiftItem?["username"] as? String
let postDesc = swiftItem?["description"] as? String
let postArray = postStruct(title: postTitle, description: postDesc, username: postUsername)
self.newPost.insert(postArray, at: 0)
}
}
}
}
Worked for me. It gets all the values now you just have to put them in an array
postDB.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull #NotNull Task<DataSnapshot> task) {
if(!task.isSuccessful()){
Log.e("firebase", "Error getting data; ", task.getException());
}else{
Log.d("firebase", String.valueOf(task.getResult().getValue()));
}
}
});

How do I filter data from my Firebase Database?

How do I change the fetchAllPosts function in my networking file and in the homeviewController so that I only get posts from the database that match the UID of the user I’m following with the post.UID, so my feed is filled with posts of users I follow?
Here is the reference showing how I make a new follower in the database:
let followingRef = "following/" + (self.loggedInUserData?["uid"] as! String) + "/" + (self.otherUser?["uid"] as! String)
Here is the post structure in the Firebase database
posts
-Ke4gQKIbow10WdLYMTL (generated key)
postDate:
postId:
postPicUrl:
postText:
postTit:
type:
uid: looking to match this
Here is the current fetchAllPosts function in the networking file
func fetchAllPosts(completion: #escaping ([Post])->()) {
let postRef = self.dataBaseRef.child("posts")
postRef.observe(.value, with: { (posts) in
var resultsArray = [Post]()
for post in posts.children {
let post = Post(snapshot: post as! FIRDataSnapshot)
resultsArray.append(post)
}
completion(resultsArray)
}) { (error) in
print(error.localizedDescription)
}
}
here is the fetchAllPosts function in the homeViewController
private func fetchAllPosts(){
authService.fetchAllPosts {(posts) in
self.postsArray = posts
self.postsArray.sort(by: { (post1, post2) -> Bool in
Int(post1.postDate) > Int(post2.postDate)
})
self.tableView.reloadData()
}
}
Here is my post structure in my swift file:
struct Post {
var username: String!
var uid: String!
var postId: String!
var type: String
var postText: String
var postTit: String
var postPicUrl: String!
var postDate: NSNumber!
var ref: FIRDatabaseReference!
var key: String = ""
init(postId: String,postText: String, postTit:String, postDate:NSNumber, postPicUrl: String?, type:String, uid: String, key: String = ""){
self.postText = postText
self.postTit = postTit
self.postPicUrl = postPicUrl
self.type = type
self.uid = uid
self.postDate = postDate
self.postId = postId
}
init(snapshot: FIRDataSnapshot){
self.ref = snapshot.ref
self.key = snapshot.key
self.postId = (snapshot.value! as! NSDictionary)["postId"] as! String
self.type = (snapshot.value! as! NSDictionary)["type"] as! String
self.postPicUrl = (snapshot.value! as! NSDictionary)["postPicUrl"] as! String
self.postDate = (snapshot.value! as! NSDictionary)["postDate"] as! NSNumber
self.postTit = (snapshot.value! as! NSDictionary)["postTit"] as! String
self.uid = (snapshot.value! as! NSDictionary)["uid"] as! String
self.postText = (snapshot.value! as! NSDictionary)["postText"] as! String
}
func toAnyObject() -> [String: Any] {
return ["postId":self.postId,"type":self.type, "postPicUrl":self.postPicUrl,"postDate":self.postDate, "postTit":self.postTit,"uid": self.uid, "postText":self.postText,]
}
}
Did you use this;
postRef.queryOrdered(byChild: "uid").queryEqual(toValue: yourUid).observe(.value, with: {
snapshot in
if let shot = snapshot {
let post = Post(snapshot: post as! FIRDataSnapshot)
}
}
This returns data you are looking for.