Segue using tableViewCells - ios

I am going to try to be as clear as I can be on this question but if you need more information please please ask. I have a tableviewcontroller that has a list of all the messages the logged in user has had with other users of the app. When clicked the logged in user clicks a cell, I would like for the user to segue to a view controller that allows them to chat with whatever user they like. This chat was acquired using JSQMessageController. However, when I set it the segue in the tableviewcontroller, show below:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let message = messages[indexPath.row]
if message.ReceiverId != self.loggedInUserUid {
var newVariable = message.ReceiverId
if self.userpicuid == newVariable {
let ref = FIRDatabase.database().reference().child("users").child(userpicuid!)
ref.observeSingleEvent(of: .value, with: { (snapshot)
in
if let dictionary = snapshot.value as? [String: AnyObject]{
for post in dictionary {
let messages = post.value as! [String: AnyObject]
for (id, value) in messages {
self.username = messages["username"] as? String
}}}})}} else if message.senderId != self.loggedInUserUid {
let newVariable = message.senderId
if self.userpicuid == newVariable {
let ref = FIRDatabase.database().reference().child("users").child(userpicuid!)
ref.observeSingleEvent(of: .value, with: { (snapshot)
in
if let dictionary = snapshot.value as? [String: AnyObject]{
for post in dictionary {
let messages = post.value as! [String: AnyObject]
for (id, value) in messages {
self.username = messages["username"] as? String
}}}})}
}
performSegue(withIdentifier: "MessageNow", sender: self.userpicuid)
}
override public func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "MessageNow", let chatVc = segue.destination as? SendMessageViewController else {
return
}
chatVc.senderId = self.loggedInUser?.uid
chatVc.receiverData = sender as AnyObject
chatVc.senderDisplayName = self.userpicuid
chatVc.username = self.username
}
I get an error in the MessageViewController:
var receiverData: AnyObject?
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
}}
I get the error on the let receiverId = receiverData as! String that:
Could not cast value of type 'Chat_App.MessageTableViewCell' (0x10eb2ef10) to 'NSString' (0x110ab1c60).
in a different view controller, I have:
#IBAction func sendMessage(_ sender: Any) {
performSegue(withIdentifier: "sendMessageToUser", sender: self.userpicuid)
}
override public func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "sendMessageToUser", let chatVc = segue.destination as? SendMessageViewController else {
return
}
chatVc.senderId = self.loggedInUser?.uid
chatVc.receiverData = sender as! String!
chatVc.senderDisplayName = self.userpicuid
chatVc.username = self.username
}
And it segues perfectly.

Sender is Any? and you're casting it to AnyObject. AnyObject refers to a class type, and it's asserting when you attempt to cast it to a Swift value type (String).
Try this instead:
chatVc.receiverData = NSString(string: sender as! String)

Your sender is the the UITableViewCell that initiated the segue. You are crashing when casting it to NSString. Remove this line
let receiverId = receiverData as! String
In prepareForSegue do this instead
chatVc.receiverData = self.userpicuid

Related

Swift when press button in cell give duplicated in other cells

Im retrieve data from firebese and show in tableView
In tavleViewCell I have butons : like, unLike
when I press like need to hide likeButton and show UnlikeButton
And store/remove data from firebase
Now I create metods and when I click Like -> data save to firebase and show unlikeButton BUT unlikeButton shows in another cell's(not in all cells- example if I click in 0 indexPath.row, unlikeButton shows in 0,6,12,17..) Maybe this may happen when I scroll tableView
in cell I have :
protocol TableThemeQuote {
func likeTap(_ sender: ThemesQuoteCell)
func unlikeTap(_ sender: ThemesQuoteCell)
}
class ThemesQuoteCell: UITableViewCell {
#IBOutlet weak var likeBtn: UIButton!
#IBOutlet weak var unlikeBtn: UIButton!
var themeDelegate: TableThemeQuote?
var index: indexPath?
#IBAction func likeBtn(_ sender: UIButton) {
sender.tag = index.row
themeDelegate?.likeTap(self)
}
#IBAction func unLikeBtn(_ sender: UIButton) {
sender.tag = index.row
themeDelegate?.unlikeTap(self)
}
}
In ViewController:
var userMarks: [String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
likeLike()
}
func likeLike() {
let userUID = Auth.auth().currentUser!.uid
let ref = Database.database().reference().child("users").child("\(userUID)")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if let properties = snapshot.value as? [String : AnyObject] {
if let peopleWhoLike = properties["userLikes"] as? [String : AnyObject] {
self.likeLikeL.append(peopleWhoLike)
for (id,person) in peopleWhoLike {
self.userLikeCheck.updateValue(person, forKey: id)
self.userMarks.append(person as! String)
}
}
}
})
}
In cellForRowAt indexPath:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "themesQuoteCell") as! ThemesQuoteCell
let index = indexPath.row
cell.index = index
cell.themeDelegate = self
let mark = "Темы/\(themeName)/\(quotenumber[index.row])"
if userMarks.contains(mark){
if cell.likeBtn.tag == index.row {
cell.likeBtn.isHidden = true
cell.unlikeBtn.isHidden = false
break
}
}
return cell
}
In TableThemeQuote extension:
extension ThemeQuoteVC: TableThemeQuote {
func likeTap(_ sender: ThemesQuoteCell) {
guard let tappedIndexPath = themeQuoteTableView.indexPath(for: sender) else { return }
let ref = Database.database().reference().child("Темы").child("\(self.themeName)").child("\(quotenumber[tappedIndexPath.row])")
let keyToPost = ref.childByAutoId().key!
let updateLikes: [String : Any] = ["peopleWhoLike/\(keyToPost)" : Auth.auth().currentUser!.uid]
ref.updateChildValues(updateLikes, withCompletionBlock: { (error, reff) in
if error == nil {
ref.observeSingleEvent(of: .value, with: { (snap) in
if let properties = snap.value as? [String : AnyObject] {
if let likes = properties["peopleWhoLike"] as? [String : AnyObject] {
let count = likes.count
sender.likeLbl.text = "\(count)"
let update = ["quant" : count]
ref.updateChildValues(update)
sender.likeBtn.isHidden = true
sender.unlikeBtn.isHidden = false
sender.likeBtn.isEnabled = true
}
}
})
}
})
ref.removeAllObservers()
}
func unlikeTap(_ sender: ThemesQuoteCell) {
sender.unlikeBtn.isEnabled = false
guard let uid = Auth.auth().currentUser?.uid else { return }
let ref = Database.database().reference().child("users").child("\(uid)")
guard let tappedIndexPath = themeQuoteTableView.indexPath(for: sender) else { return }
let mark = "Темы/\(themeName)/\(quotenumber[tappedIndexPath.row])"
unlikeCellBtn(index: tappedIndexPath.row, sender: sender)
if sender.unlikeBtn.tag == tappedIndexPath.row {
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if let properties = snapshot.value as? [String : AnyObject] {
if let peopleWhoLike = properties["userLikes"] as? [String : AnyObject] {
for (id,person) in peopleWhoLike {
if person as! String == mark {
ref.child("userLikes").child(id).removeValue(completionBlock: { (error, reff) in
if error == nil {
ref.observeSingleEvent(of: .value, with: { (snap) in
if let prop = snap.value as? [String : AnyObject] {
if let likes = prop["userLikes"] as? [String : AnyObject] {
let count = likes.count
ref.updateChildValues(["quantLikes" : count])
}else {
ref.updateChildValues(["quantLikes" : 0])
}
}
})
}
})
sender.likeBtn.isHidden = false
sender.unlikeBtn.isHidden = true
sender.unlikeBtn.isEnabled = true
break
}
}
}
}
})
}
ref.removeAllObservers()
}
What Im doing wrong and how can I get current tap and show/hide only that button which I press?
Cells are reused. This part of the code
if userMarks.contains(mark){
if cell.likeBtn.tag == index.row {
cell.likeBtn.isHidden = true
cell.unlikeBtn.isHidden = false
break
}
}
sets the hidden properties depending on some conditions but keeps the hidden state unchanged if the conditions are not met.
What you have to do is to add an else clause to set default values (by the way, the break statement is pointless)
if userMarks.contains(mark) && cell.likeBtn.tag == index.row {
cell.likeBtn.isHidden = true
cell.unlikeBtn.isHidden = false
} else {
cell.likeBtn.isHidden = <default value>
cell.unlikeBtn.isHidden = <default value>
}

Swift Firebase "Cannot assign value of type 'Information' to type 'NSDictionary?'"

I have a tableview that is being populated with who a user is following. Problem is that I need to pass that cells data to "var otherUser: NSDictionary!" but because I am populating the cell using a data structure file called "Information" I get this error - "Cannot assign value of type 'Information' to type 'NSDictionary?'" in the prepareForSegue. I am unsure if I can repackage the information I need into a NSDictionary so I can successfully do a data pass. I just don't know if this is a easy solution or an actual problem because of my ignorance.
Following TableViewController Code
import UIKit
import Firebase
class BusinessFollowing: UITableViewController {
#IBOutlet var noDataView: UIView!
#IBOutlet var followingTableView: UITableView!
var yourFollowing = [Information]()
var listFollowing = [NSDictionary?]()
var databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
var loggedInUser = Auth.auth().currentUser
var loggedInUserData:NSDictionary?
var following = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.followingTableView.backgroundView = nil
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.followingTableView.reloadData()
self.yourFollowing.removeAll()
self.following.removeAll()
getFollowingData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "following" {
// gotta check if we're currently searching
if let indexPath = followingTableView.indexPathForSelectedRow {
let user = self.yourFollowing[indexPath.row]
let controller = segue.destination as? ExploreBusinessProfileSwitchView
controller?.otherUser = user
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.yourFollowing.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! BusinessFollowingCell
let following = yourFollowing[indexPath.row]
let businessName = following.businessName
let businessStreet = following.businessStreet
let businessCity = following.businessCity
let businessState = following.businessState
cell.businessName.text = businessName
cell.businessStreet.text = businessStreet
cell.businessCity.text = businessCity
cell.businessState.text = businessState
// cell.businessName?.text = self.listFollowing[indexPath.row]?["businessName"] as? String
// cell.businessStreet?.text = self.listFollowing[indexPath.row]?["businessStreet"] as? String
// cell.businessCity?.text = self.listFollowing[indexPath.row]?["businessCity"] as? String
// cell.businessState?.text = self.listFollowing[indexPath.row]?["businessState"] as? String
return cell
}
func getFollowingData() {
self.yourFollowing.removeAll()
self.following.removeAll()
self.followingTableView.reloadData()
Database.database().reference().child("Businesses").child((loggedInUser?.uid)!).child("following").observe(.value, with: { snapshot in
if snapshot.exists() {
MBProgressHUD.showAdded(to: self.view, animated: true)
let databaseRef = Database.database().reference()
databaseRef.child("Businesses").queryOrderedByKey().observeSingleEvent(of: .value, with: { (usersSnapshot) in
let users = usersSnapshot.value as! [String: AnyObject]
for (_, value) in users {
if let userID = value["uid"] as? String {
if userID == Auth.auth().currentUser?.uid {
print(value)
if let followingUsers = value["following"] as? [String : String] {
for (_,user) in followingUsers {
self.following.append(user)
}
}
databaseRef.child("following").queryOrderedByKey().observeSingleEvent(of: .value, with: { (postsSnapshot) in
let posts = postsSnapshot.value as! [String: AnyObject]
for (_, post) in posts {
for (_, postInfo) in post as! [String: AnyObject] {
if let followingID = postInfo["uid"] as? String {
for each in self.following {
if each == followingID {
guard let uid = postInfo["uid"] as! String? else {return}
guard let name = postInfo["businessName"] as! String? else {return}
guard let address = postInfo["businessStreet"] as! String? else {return}
guard let state = postInfo["businessState"] as! String? else {return}
guard let city = postInfo["businessCity"] as! String? else {return}
self.yourFollowing.append(Information(uid: uid, businessName: name, businessStreet: address, businessCity: city, businessState: state))
}
self.followingTableView.backgroundView = nil
self.followingTableView.reloadData()
}
}
}
}
MBProgressHUD.hide(for: self.view, animated: true)
}) { (error) in
print(error.localizedDescription)
}
}
}
}
})
} else {
print("Not following anyone")
self.followingTableView.backgroundView = self.noDataView
MBProgressHUD.hide(for: self.view, animated: true)
}
})
}
}
"Information" Data Structure File
import UIKit
class Information {
var uid: String
var businessName: String
var businessStreet: String
var businessCity: String
var businessState: String
init(uid: String, businessName: String, businessStreet: String, businessCity: String, businessState: String){
self.uid = uid
self.businessName = businessName
self.businessStreet = businessStreet
self.businessCity = businessCity
self.businessState = businessState
}
}
The error is pretty clear.
user in ExploreBusinessProfileSwitchView is obviously declared as NSDictionary, declare it as Information.
By the way don't use NSArray / NSDictionary in Swift. Use native types.

Swift Firebase TableView Data - DataEventType.value

I am doing a call into a child "following" and am seeing if the logged-in user's UID is there and has a child of another user which the logged-in user is following.
I am printing who the logged-in user is following into a tableview. The first problem is my code, because I know it is bad practice to have two firebase calls within each other so I need someone to teach me a better method. Because of the poor code, when I go unfollow the other user and come back to the tab where the logged-in users list of who they are following is displayed it shows this (image below). When the logged-in user is following nobody it should just display the "Sorry!" text, yet still keeps who the user was following. Need someone to teach me a better method for doing this type of firebase call. Code and a firebase JSON stack image are below... In the firebase JSON stack image, the expanded UID is the logged-in user and the child in is the other user the logged-in user is following. I need a better way to call and extract this information, I am just ignorant of how-to.
func getFollowingData() {
Database.database().reference().child("following").child(uid!).observe(DataEventType.value, with: { (snapshot) in
if snapshot.exists() {
print("Got Snapshot")
Database.database().reference().child("following").child(self.uid!).observe(.childAdded, with: { (snapshot) in
if snapshot.exists() {
print(snapshot)
let snapshot = snapshot.value as? NSDictionary
self.listFollowing.append(snapshot)
self.followingTableView.insertRows(at: [IndexPath(row:self.listFollowing.count-1,section:0)], with: UITableViewRowAnimation.automatic)
self.followingTableView.backgroundView = nil
}
})
} else {
print("No Snapshot")
self.followingTableView.backgroundView = self.noDataView
}
})
}
Figured it out, just needed to do it how I did it before on other feeds.
import UIKit
import Firebase
class BusinessFollowing: UITableViewController {
#IBOutlet var noDataView: UIView!
#IBOutlet var followingTableView: UITableView!
var yourFollowing = [Information]()
var listFollowing = [NSDictionary?]()
var databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
var loggedInUser = Auth.auth().currentUser
var loggedInUserData:NSDictionary?
var following = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.followingTableView.backgroundView = nil
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.followingTableView.reloadData()
self.yourFollowing.removeAll()
self.following.removeAll()
getFollowingData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "following" {
// gotta check if we're currently searching
if let indexPath = followingTableView.indexPathForSelectedRow {
let user = listFollowing[indexPath.row]
let controller = segue.destination as? ExploreBusinessProfileSwitchView
controller?.otherUser = user
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.yourFollowing.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! BusinessFollowingCell
let following = yourFollowing[indexPath.row]
let businessName = following.businessName
let businessStreet = following.businessStreet
let businessCity = following.businessCity
let businessState = following.businessState
cell.businessName.text = businessName
cell.businessStreet.text = businessStreet
cell.businessCity.text = businessCity
cell.businessState.text = businessState
// cell.businessName?.text = self.listFollowing[indexPath.row]?["businessName"] as? String
// cell.businessStreet?.text = self.listFollowing[indexPath.row]?["businessStreet"] as? String
// cell.businessCity?.text = self.listFollowing[indexPath.row]?["businessCity"] as? String
// cell.businessState?.text = self.listFollowing[indexPath.row]?["businessState"] as? String
return cell
}
func getFollowingData() {
self.yourFollowing.removeAll()
self.following.removeAll()
self.followingTableView.reloadData()
Database.database().reference().child("Businesses").child((loggedInUser?.uid)!).child("following").observe(.value, with: { snapshot in
if snapshot.exists() {
MBProgressHUD.showAdded(to: self.view, animated: true)
let databaseRef = Database.database().reference()
databaseRef.child("Businesses").queryOrderedByKey().observeSingleEvent(of: .value, with: { (usersSnapshot) in
let users = usersSnapshot.value as! [String: AnyObject]
for (_, value) in users {
if let userID = value["uid"] as? String {
if userID == Auth.auth().currentUser?.uid {
print(value)
if let followingUsers = value["following"] as? [String : String] {
for (_,user) in followingUsers {
self.following.append(user)
}
}
databaseRef.child("following").queryOrderedByKey().observeSingleEvent(of: .value, with: { (postsSnapshot) in
let posts = postsSnapshot.value as! [String: AnyObject]
for (_, post) in posts {
for (_, postInfo) in post as! [String: AnyObject] {
if let followingID = postInfo["uid"] as? String {
for each in self.following {
if each == followingID {
guard let uid = postInfo["uid"] as! String? else {return}
guard let name = postInfo["businessName"] as! String? else {return}
guard let address = postInfo["businessStreet"] as! String? else {return}
guard let state = postInfo["businessState"] as! String? else {return}
guard let city = postInfo["businessCity"] as! String? else {return}
self.yourFollowing.append(Information(uid: uid, businessName: name, businessStreet: address, businessCity: city, businessState: state))
}
self.followingTableView.backgroundView = nil
self.followingTableView.reloadData()
}
}
}
}
MBProgressHUD.hide(for: self.view, animated: true)
}) { (error) in
print(error.localizedDescription)
}
}
}
}
})
} else {
print("Not following anyone")
self.followingTableView.backgroundView = self.noDataView
MBProgressHUD.hide(for: self.view, animated: true)
}
})
}
}

Could not cast value of type 'TableViewController' to 'NSString'

I'm getting following error in the fourth line of below code...
Thread 1: signal SIGABRT, and the output says Could not cast value of type 'JobTableViewController' (0x10a20cb80) to 'NSString' (0x10cc5a2a8).
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetails" {
let detailController = segue.destination as! JobDetailViewController
detailController.valueToPass = sender as! String
}
}
Job.swift:
class Job {
var text: String = ""
let ref: DatabaseReference!
init(text: String) {
self.text = text
ref = Database.database().reference().child("jobs").childByAutoId()
}
init(snapshot: DataSnapshot)
{
ref = snapshot.ref
if let value = snapshot.value as? [String : Any] {
text = value["text"] as! String
}
}
func save() {
ref.setValue(toDictionary())
}
func toDictionary() -> [String : Any]
{
return [
"text" : text,
]
}
}
Your problem is that in performSegue you send self ( which is of type JobTableViewController) as sender parameter like this
self.performSegue(withIdentifier: "toDetails", sender: self)
and here cast it to
sender as! String
so convert it to
self.performSegue(withIdentifier: "toDetails", sender:"sendedStr")

segue to specific Firebase data

I have a tableView and it has about 5 cells and each cell has a different subject. Upon clicking on the cell, I will like to segue to a view controller that is populated with Firebase data only containing posts that has the specific subject clicked.
override func viewDidLoad() {
super.viewDidLoad()
FIRDatabase.database().reference().child("books").observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
if let postsDictionary = snapshot .value as? [String: AnyObject] {
self.Category = postsDictionary["Category"] as? String ?? ""
}})
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segue" {
let showBooks = segue.destination as! SearchTableViewController
showBooks.categorySegue = self.Category
}
}
In my Firebase database, I have a bunch of posts made by different users and in every post, they set the category to which the post belongs to. For example, if I click on the tableView cell that has the subject: Economics, I would like to segue to a view controller that only has the Economics category.
This is how I retrieve the post attributed to certain subjects:
databaseRef.child("books").queryOrdered(byChild: "category").queryEqual(toValue: categorySegue).observeSingleEvent(of: .value, with: { (snapshot) in
let key = snapshot.key
let snapshot = snapshot.value as? NSDictionary
snapshot?.setValue(key, forKey: "uid")
if(key == self.loggedUser?.uid)
{
print("same as logged in user")
}
else
{
self.usersArray.append(snapshot)
self.followUsersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1,section:0)], with: UITableViewRowAnimation.automatic)
}
}) { (error) in
print(error.localizedDescription)
}
tableView.tableFooterView = UIView()
If the category is directly below the posts node under a uniqueID, then try this
Example :
posts
-> post_id1
->category : "books"
-> other keys
-> post_id2
->category : "music"
-> other keys
The query to fetch the posts by category will be like this,
let strCategory = "music"
baseRef.child("posts").queryOrdered(byChild: "category").queryEqualToValue(strCategory).observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
})
To get the cell index on selection,
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let indexPath = tableView.indexPathForSelectedRow{
let selectedRow = indexPath.row
let categorySelected = Subjects[selectedRow]
}
}

Resources