Hi guys I'm really having troubles trying to pass data from a tableview to another view controller. I have a tableview that displays a list of every user but when I click on a user it goes to the next view controller without showing any data of that particular user. The code below is pretty much the same from an example I followed but for some reason its not working for me. Please help, I've tried searching for solutions but can't find anything. Im also using firebase to store and retrieve my data. Thanks in advance
#IBOutlet weak var searchTableView: UITableView!
var profiles = [user]()
var ref: FIRDatabaseReference!
override func viewdidload(){
databaseRef = FIRDatabase.database().reference()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "guestSegue", sender: self)
self.searchTableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "guestSegue" {
if let indexpath = searchTableView.indexPathForSelectedRow {
let guestVC = segue.destination as! guestProfileViewController
guestVC.ref = profiles[indexpath.row].ref
}
}
}
user array
class User {
var backgroundProfileImage: String!
var fullName: String!
var profilePic: String!
var ref: FIRDatabaseReference!
var key: String
init(backgroundProfileImage: String, fullName: String, profilePic: String, key: String = ""){
self.backgroundProfileImage = backgroundProfileImage
self.fullName = fullName
self.profilePic = profilePic
self.key = key
self.ref = FIRDatabase.database().reference()
}
init(snapshot: FIRDataSnapshot){
self.backgroundProfileImage = value["backgroundProfileImage"] as! String!
self.fullName = (snapshot.value as! NSDictionary)["fullName"] as! String
self.profilePic = (snapshot.value as! NSDictionary)["profilePic"] as! String
self.uid = (snapshot.value as! NSDictionary)["uid"] as! String!
self.key = snapshot.key
self.ref = snapshot.ref
}
guestViewController
class guestProfileViewController: UIViewController, UINavigationControllerDelegate {
#IBOutlet weak var profileImage: UIImage!
#IBOutlet weak var backgroundProfileImage: UIImageView!
#IBOutlet weak var fullNameLabel: UILabel!
var ref: FIRDatabaseReference?
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
loadProfileData()
}
func loadProfileData(){
if let ref = ref {
ref.observe(.value, with: { (user) in
let user: User = User(snapshot: user)
self.fullNameLabel.text = user.fullName
self.profileImage.sd_setImage(with: URL(string: user.profilePic), placeholderImage: UIImage(named: "default"))
self.backgroundProfileImage.sd_setImage(with: URL(string: user.backgroundProfileImage), placeholderImage: UIImage(named: "default_1"))
})
}
}
}
ref is being set in viewDidLoad() of guestProfileViewController. Try removing that bit as it seems like you want ref to equal the User's ref.
Related
I have a tableview that presents events that a user creates. When you click on one of them it takes you to a different page that presents the details of the event.
I'm using Firebase and passing the postID from the tableview to the detailed view and all the information is being passed correctly in an NSDictionary.
However, when I try to access the NSDictionary out of the viewDidLoad and in an IBAction it tells me that the NSDictionary is nil. When I check in the viewDidLoad it is not nil.
I'm very new to programming and learning along the way but I've been stuck on this for a while now and have no idea whats wrong or how I can fix it
this is my code
import UIKit
import Firebase
class BeehiveViewViewController: UIViewController {
#IBOutlet weak var eventImage: UIImageView!
#IBOutlet weak var eventName: UILabel!
#IBOutlet weak var location: UILabel!
#IBOutlet weak var eventDate: UILabel!
#IBOutlet weak var eventHost: UILabel!
#IBOutlet weak var members: UILabel!
#IBOutlet weak var joinButton: roundButton!
var beehiveID: NSDictionary?
var ref = Database.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
view.setGradientBackground(colourOne: primaryColor, colourTwo: secondaryColor)
let uid = Auth.auth().currentUser?.uid
ref.child("users").child(uid!).child(self.beehiveID?["pid"] as! String).observe(.value) { (snapshot) in
let uid = self.beehiveID!["pid"] as! String
self.beehiveID = snapshot.value as? NSDictionary
self.beehiveID?.setValue(uid, forKey: "pid")
}
let imageURL = self.beehiveID!["imageDownloadURL"] as! String
let url = URL(string: imageURL)
DispatchQueue.global(qos: .background).async {
let data = NSData(contentsOf: url!)
DispatchQueue.main.async {
self.eventImage.image = UIImage(data: data! as Data)
}
}
self.eventName.text = self.beehiveID?["eventName"] as? String
self.eventDate.text = self.beehiveID?["eventDate"] as? String
self.eventHost.text = self.beehiveID?["beehiveHost"] as? String
self.location.text = self.beehiveID?["location"] as? String
let uidd = Auth.auth().currentUser?.uid
Database.database().reference().child("users").child(uidd!).child("Posts").child(self.beehiveID?["pid"] as! String).child("Members").observe(.value) { (snapshot) in
let memberCount = snapshot.childrenCount
self.members.text = "\(memberCount)"
}
let userID = Auth.auth().currentUser?.uid
Database.database().reference().child("users").child(userID!).child("Posts").child(self.beehiveID?["pid"] as! String).observe(.value) { (snapshot) in
print(snapshot)
if (snapshot.exists()){
self.joinButton.setTitle("Remove Beehive", for: .normal)
}
else{
self.joinButton.setTitle("Join Beehive", for: .normal)
}
}
}
#IBAction func buttonPressed(_ sender: Any) {
if joinButton.titleLabel?.text == "Remove Beehive"{
let uid = Auth.auth().currentUser?.uid
let dbref = ref.child("users").child(uid!).child("Posts").child(beehiveID?["pid"] as! String)
//error is the line above that beehiveID?["pid"] is nil
dbref.removeValue()
navigationController?.popViewController(animated: true)
}
if joinButton.titleLabel?.text == "Join Beehive"{
let uid = Auth.auth().currentUser?.uid
let dbref = Database.database().reference().child("users").child(uid!).child("Posts").child("Members")
Database.database().reference().child("users").child(uid!).child("Name").observe(.value) { (nameSnapshot) in
let memberName = nameSnapshot.value as! String
let userObject = [memberName: uid]
dbref.updateChildValues(userObject as! [AnyHashable : String])
}
}
}
}
I assume that you're passing beeHive's value from the previous controller as you haven't initialised or got the values of it anywhere:-
Try having a breakpoint right before the end of viewDidLoad to double-check if the dictionary isn't nil at the block
self.beehiveID = snapshot.value as? NSDictionary
Try using a check to see if the snapshot's value is nil using 'if let' or 'guard' as you could possibly just be assigning a nil value to the NSDictionary. Also, since you're using optionals for assigning each value, it doesn't return an exception but just keeps assigning the nil value to every property
Do try this and let me know. Glad to help!
I’m having trouble passing data via prepareForSegue from MainVC to EditVC. The gist of the problem is I’m trying to edit quote info(quote and author) already entered(saved in a Firestore database). When swiping(UIContextualAction) and tap on edit, it’s suppose to pass the data on to the EditVC where it’ll put the quote text and author text in their own UITextView where it’s editable. Once you edit the text, hit save and it’ll update the entry in Firestore; then MainVC reloads to update it’s view. The segue to the EditVC works flawlessly but it doesn’t display the quote & author text in their respective text views. I’ve been banging my head against the wall for 3 days trying to figure it out. Any help or guidance from you all is greatly appreciated. I can provide the Github link upon request.
MainVC:
}
let edit = UIContextualAction(style: .normal, title: "Edit") { (action, view, nil) in
self.performSegue(withIdentifier: "toEditQuote", sender: self.quotes)
print("Segue initiated")
}
edit.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
return UISwipeActionsConfiguration(actions: [delete, edit])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
print("preparing to segue")
if let destination = segue.destination as? EditQuoteVC {
print("Destination = EditQuoteVC")
if let quoteData = sender as? Quote {
print("data passing")
destination.quoteTxt = quoteData.quoteTxt
destination.authorTxt = quoteData.authorTxt
print("data passed")
}
}
}
}
EditQuoteVC(destination)
class EditQuoteVC: UIViewController {
//Outlets
#IBOutlet weak var quoteText: UITextView!
#IBOutlet weak var authorText: UITextView!
//Variables
var quoteTxt: String!
var authorTxt: String!
override func viewDidLoad() {
super.viewDidLoad()
quoteText.text = quoteTxt
authorText.text = authorTxt
}
Quote.swift
class Quote {
private(set) var quoteTxt: String!
private(set) var authorTxt: String!
private(set) var timestamp: Date!
private(set) var userId: String!
private(set) var documentID: String!
init(quote: String, author: String, timestamp: Date, userId: String, documentID: String) {
self.quoteTxt = quote
self.authorTxt = "- \(author)"
self.timestamp = timestamp
self.userId = userId
self.documentID = documentID
}
class func parseData(snapshot: QuerySnapshot?) -> [Quote] {
var quotes = [Quote]()
guard let snap = snapshot else { return quotes}
for document in snap.documents { //Grabs the documents...
let data = document.data()
let quote = data[QUOTE_TEXT] as? String ?? ""
let author = data[AUTHOR_TEXT] as? String ?? ""
let timestamp = data[TIMESTAMP] as? Date ?? Date()
let userId = data[USER_ID] as? String ?? ""
let documentID = document.documentID
let newQuote = Quote(quote: quote, author: author, timestamp: timestamp, userId: userId, documentID: documentID)
quotes.append(newQuote)
}
return quotes
}
}
In your prepareForSegue function, you are assigning destination to sender. It should be:
if let destination = segue.destination as? EditQuoteVC
I have now tried everything (as far as I know), I even made the whole thing from scratch, but it still doesn´t work.
I have made a search bar which can search for data in firebase and display them in a tableview. If the user clicks on a profile in the search bar, a new viewcontroller shows with information about that user.
The problem is that if you start searching, then clicks on a profile, it shows the profile which started on that position in the tableview before the search happened.
This is what I see without searching, it displays the 2 profiles in firebase which is correct:
Now, when I search for the profile "Lars Larsen" it filters like it should:
However, if I now choose the profile by clicking on "Lars Larsen" it shows the profile for "Jonas Larsen", which was at the top before the search?
This is the code for my searchViewController:
import UIKit
import FirebaseDatabase
class SearchTableViewController: UITableViewController,
UISearchResultsUpdating {
let searchController = UISearchController(searchResultsController: nil)
#IBOutlet var findKunder: UITableView!
var loggedInUser: user?
var usersArray = [NSDictionary?]()
var filteredUsers = [NSDictionary?]()
var databaseRef = Database.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
databaseRef.child("Buyers").queryOrdered(byChild: "Personnr").observe(.childAdded, with: { (snapshot) in
let key = snapshot.key
let snapshot = snapshot.value as? NSDictionary
snapshot?.setValue(key, forKey: "Personnr")
self.usersArray.append(snapshot)
//Insert rows
self.findKunder.insertRows(at: [IndexPath(row:self.usersArray.count-1,section:0)], with: UITableViewRowAnimation.automatic)
}) { (error) in
print(error)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
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
if searchController.isActive && searchController.searchBar.text != ""{
return filteredUsers.count
}
return self.usersArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let user : NSDictionary?
if searchController.isActive && searchController.searchBar.text != ""{
user = filteredUsers[indexPath.row]
}
else
{
user = self.usersArray[indexPath.row]
}
cell.textLabel?.text = user? ["Navn"] as? String
cell.detailTextLabel?.text = user?["Telefonnr"] as? String
// Configure the cell...
return cell
}
func updateSearchResults(for searchController: UISearchController) {
filterContent(searchText: self.searchController.searchBar.text!)
}
func filterContent(searchText:String)
{
self.filteredUsers = self.usersArray.filter{ user in
var fNavn = false
var personNr = false
var searchBil = false
var telefonNr = false
var korekortNr = false
if let Navn = user!["Navn"] as? String {
fNavn = Navn.lowercased().contains(searchText.lowercased())
}
if let Bil = user!["Bil"] as? String {
searchBil = Bil.lowercased().contains(searchText.lowercased())
}
if let Personnr = user!["Personnr"] as? String {
personNr = Personnr.lowercased().contains(searchText.lowercased())
}
if let Kørekortnr = user!["Kørekortnr"] as? String {
korekortNr = Kørekortnr.lowercased().contains(searchText.lowercased())
}
if let Telefonnr = user!["Telefonnr"] as? String {
telefonNr = Telefonnr.lowercased().contains(searchText.lowercased())
}
return fNavn || personNr || searchBil || korekortNr || telefonNr
}
tableView.reloadData()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
let showUserProfileViewController = segue.destination as! userProfileViewController
showUserProfileViewController.loggedInUser = self.loggedInUser
if let indexPath = tableView.indexPathForSelectedRow {
let user = usersArray[indexPath.row]
showUserProfileViewController.otherUser = user
}
}
}
This is the code I use to show the profiles:
import UIKit
import Firebase
class ProfileViewController: UIViewController {
//Outlets
var loggedInUser:User?
var otherUser:NSDictionary?
var databaseRef:DatabaseReference!
var loggedInUserData: NSDictionary?
#IBOutlet weak var Biler: UILabel!
#IBOutlet weak var Navn: UILabel!
#IBOutlet weak var kundeInfo: UILabel!
#IBOutlet weak var bilInfo: UILabel!
#IBOutlet weak var telefonNr: UILabel!
#IBOutlet weak var korekortNr: UILabel!
#IBOutlet weak var personNr: UILabel!
#IBOutlet weak var Interesse: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.databaseRef = Database.database().reference()
databaseRef.child("Buyers").child(self.otherUser?["Personnr"] as! String).observe(.value, with: { (snapshot) in
let uid = self.otherUser?["Personnr"] as! String
self.otherUser = snapshot.value as? NSDictionary
self.otherUser?.setValue(uid, forKey: "Personnr")
self.Navn.text = self.otherUser?["Navn"] as? String
self.bilInfo.text = self.otherUser?["Bil"] as? String
self.telefonNr.text = self.otherUser?["Telefonnr"] as? String
self.Interesse.text = self.otherUser?["Interesse"] as? String
self.personNr.text = self.otherUser?["Personnr"] as? String
self.korekortNr.text = self.otherUser?["Kørekortnr"] as? String
}
// Do any additional setup after loading the view.
)}
Please let me know if you need any other information. I hope you can help.
If the search bar is active and it does contain text, you should pass a user to ProfileViewController from the filteredUsers array and not usersArray.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
[...]
if let indexPath = tableView.indexPathForSelectedRow {
if searchController.isActive && searchController.searchBar.text != "" {
showUserProfileViewController.otherUser = filteredUsers[indexPath.row]
} else {
showUserProfileViewController.otherUser = usersArray[indexPath.row]
}
}
}
On a side note, you shouldn't us NSDictionary in Swift. Use Swift's Dictionary instead (for your case, if would be [String: Any]).
If I'm understanding your code correctly, your issue is here:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
let showUserProfileViewController = segue.destination as! userProfileViewController
showUserProfileViewController.loggedInUser = self.loggedInUser
if let indexPath = tableView.indexPathForSelectedRow {
let user = usersArray[indexPath.row]
showUserProfileViewController.otherUser = user
}
}
let user = usersArray[indexPath.row] // this is wrong
Since you filtered the results if the search bar is active you have to use your updated datasource
let user = filteredUsers[indexPath.row]
Basically, you're passing the wrong information before you segue.
I'm new to ios dev and i'm trying to develop my first app! :)
so far so good...
Now I'm trying to pass data from main controller to the item details view.
It seems i can't figure out what i'm doing wrong but i keep getting an error:
"fatal error: unexpectedly found nil while unwrapping an Optional value"
now i understand that the value is not assigned but i don't understand why...
here's my code:
-------> MainVC
struct Ananlysys {
var descrizione: String!
var data: String!
var immagine: String!
var seganle: String!
var oraUpload: String!
var valuta: String!
}
var analysisList = [Ananlysys]()
var alertsRef = FIRDatabase.database().reference().child("analisi")
override func viewDidLoad() {
super.viewDidLoad()
fetchDataFromDB()
}
func fetchDataFromDB(){
alertsRef.observe(.childAdded, with: { snapshot in
if let dict = snapshot.value as? [String: AnyObject] {
let descrizione = dict["descrizione"] as! String
let data = dict["data"] as! String
let stato = dict["stato"] as! String
let immagine = dict["imageURL"] as! String
let seganle = dict["segnale"] as! String
let oraUpload = dict["oraupload"] as! String
let valuta = dict["valuta"] as! String
self.analysisList.insert(Ananlysys(descrizione: descrizione,
data:data, immagine:immagine, seganle: seganle, oraUpload: oraUpload,
valuta: valuta), at: 0)
self.tableView.reloadData()
}
})
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ItemDetailVC"{
if let indexPath = self.tableView.indexPathForSelectedRow {
let destination = segue.destination as! ItemDetailVC
let cell = tableView.cellForRow(at: indexPath) as? ItemCell
destination.valuta = (cell?.valutaLabel.text)!
destination.segnale = (cell?.signalLabel.text)!
destination.desc = (cell?.descriptionLabel.text)!
destination.immagine = (cell?.imageThumb.image)!
}
}
And in My ItemDetailsVC controller (which is the destination) i've just created the IBoutlet. Here' the code:
class ItemDetailVC: OpenAlertsVC {
#IBOutlet weak var crossLabel: UILabel!
#IBOutlet weak var signalLbl: UILabel!
#IBOutlet weak var imageDetail: UIImageView!
#IBOutlet weak var analysisDesc: UILabel!
var valuta = ""
var segnale = ""
var immagine: UIImage!
var desc = ""
}
override func viewDidLoad() {
super.viewDidLoad()
crossLabel.text = valuta
signalLbl.text = segnale
analysisDesc.text = desc
imageDetail.image = immagine
}
Probably i'm just doing some stupid error... :) but it's my first app and i really don't know how to figure this out!
If anybody could help that would be much appreciate! :)
Thank you!
Cheers!
UPDATE:
I think my problems is because of the image.
I have an url which i retrive from firebase in this way:
let url = analysisList[indexPath.row].immagine
and then i download async the images:
cell.imageThumb.downloadImageFrom(link: url!, contentMode:
UIViewContentMode.scaleToFill)
in the segue i do this:
destination.immagine = (cell?.imageThumb.image)!
and in my DetailVC:
var immagine: UIImage!
imageDetail.image = immagine
this is the screen of the error
enter image description here
Saw this recently passing variables between views. I was able to get them moving by first setting the value to a top level variable (when a row is selected) and then re-reference that variable during the segue prepare function. Hope this helps.
Set a top level variable:
var valuta: String!
Breakout the self.tableView.indexPathForSelectedRow section into it's own delegate. This tutorial is a great example. (http://shrikar.com/swift-ios-tutorial-uisearchbar-and-uisearchbardelegate)
Using the "didSelectRowAt indexPath" delegate, set the top level variable value.
func tableView(_ tableView: UITableView, didSelectRowAt IndexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)!
valuta = cell?.valutaLabel.text
}
Sample adjustments to the prepare function:
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.identifier == "ItemDetailVC"{
if let destination =
segue.destination as? name_of_your_next_view_controller {
destination.passedValuta = valuta
}
}
Make sure to put a receiving variable in the next view
var passedValuta: String!
I have my upload code here
import UIKit
import Firebase
class ChatViewController: UIViewController {
let chatRef = FIRDatabase.database().reference().child("chat")
let userUid = FIRAuth.auth()?.currentUser?.uid
var userName = ""
#IBOutlet weak var topBar: UINavigationItem!
#IBOutlet weak var containerView: UIView!
#IBOutlet var inputTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
topBar.title = "Chat Log Controller"
FIRDatabase.database().reference().child("users/\(userUid!)/name").observe(.value) { (snap: FIRDataSnapshot) in
self.userName = (snap.value! as! String).description
}
}
#IBAction func handleSend(_ sender: AnyObject) {
let childChatRef = chatRef.childByAutoId()
let message = inputTextField.text!
childChatRef.child("text").setValue(message)
print(inputTextField.text)
}
#IBAction func handleSendByEnter(_ sender: AnyObject) {
let childChatRef = chatRef.childByAutoId()
let message = inputTextField.text!
print(userName)
childChatRef.child("name").setValue(userName)
childChatRef.child("text").setValue(message)
print(inputTextField.text)
}
}
text is successfully uploaded But
It doesn't print userName and doesn't upload it to Firebase Database
But username is nut nil!
Try to use your observer code as,
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
}
Just take self.username = snap.value! as! String
It will solve your problem.