Very big thanks in advance to anyone who can help me, very much appreciated!
I am building a dating app and I am trying to have my matches load in a table after a parse query. The expected result is that the table view contains the match image and the match ID. Right now I have code for that working perfectly below.
import UIKit
import Parse
class MyListViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate {
var images = [UIImage]()
var userIds = [String]()
#IBOutlet weak var tView: UITableView!
#IBAction func toSwiperButton(_ sender: Any) {
performSegue(withIdentifier: "ToSwiper", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
let query = PFUser.query()
query?.whereKey("objectId", containedIn: PFUser.current()?["accepted"]
as! [String])
query?.findObjectsInBackground(block: { (objects, error) in
if let users = objects {
for object in users {
if let user = object as? PFUser {
let imageFile = user["photo"] as! PFFile
imageFile.getDataInBackground(block: { (data, error) in
if let imageData = data {
self.images.append(UIImage(data: imageData)!)
self.userIds.append(user.objectId!)
self.tView.reloadData()
}
})
}
}
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
internal func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return images.count
}
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PDPLIstViewTableViewCell
cell.Image.image = images[indexPath.row]
cell.id.text = userIds[indexPath.row]
return cell
}
}
The problem arises when I try to include two additional labels onto the table view for "name" and for "age" - I cant seem to figure the correct way to call them in the query in Parse along with the working photo query.
The result I want is for every cell in the table to have an image (code is working) Id (code is working) Name (code not working) and age (code not working)
By "not working" what I mean is I get a ton of errors when I try o create the variable for age from the parse data so I can pass it into the array so that my tableview can display the text next to the image.
Here is what I have been using for non working code on the "Age" label, I believe the error is where I am trying to pull the name/age using "= data" and I have to use a different term?
import UIKit
import Parse
class MyListViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate {
var images = [UIImage]()
var userIds = [String]()
var name = [String]()
var age = [String]()
#IBOutlet weak var tView: UITableView!
#IBAction func toSwiperButton(_ sender: Any) {
performSegue(withIdentifier: "ToSwiper", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
let query = PFUser.query()
query?.whereKey("objectId", containedIn: PFUser.current()?["accepted"]
as! [String])
query?.findObjectsInBackground(block: { (objects, error) in
if let users = objects {
for object in users {
if let user = object as? PFUser {
let ageFile = user["age"] as! PFFile
ageFile.getDataInBackground(block: { (data, error) in
if let ageData = data {
self.age.append(UILabel(data: ageData)!)
}
let imageFile = user["photo"] as! PFFile
imageFile.getDataInBackground(block: { (data, error) in
if let imageData = data {
self.images.append(UIImage(data: imageData)!)
self.userIds.append(user.objectId!)
self.age.append(String(data: ageFile))
self.tView.reloadData()
}
})
}
}
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
internal func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return images.count
}
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for:
indexPath) as! PDPLIstViewTableViewCell
cell.image.image = images[indexPath.row]
cell.id.text = userIds[indexPath.row]
cell.name.text = name[indexPath.row]
cell.age.text = age[indexPath.row]
return cell
}
}
You are reloading the tableview in the loop (a lot), also you do not reload when ageData is complete. Try reloading the tableview once, once the query is done. In the:
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
guard let ageFile = age[indexPath.row] as? PFFile else { return }
ageFile.getDataInBackground(block: { (data, error) in
if let ageData = data {
cell.age.text = ageData
}
}
Related
I am trying to retrieve data from firebase and display them in a tableview but my code for some reason is not working. I am getting the images and appending them into a list but that list is not having any data outside the else block.
With my implementation, I am getting a blank tableview. Could someone help with me this please?
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
let db = Firestore.firestore()
var usersReference = Firestore.firestore().collection("users")
var storageReference = Storage.storage().reference()
var imagesList = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
usersReference.addSnapshotListener { [self] (querySnapshot, error) in
querySnapshot?.documents.forEach() {
(document) in
let uid = document.data()["uid"] as! String
let imagePath = "profilePictures/\(uid).jpg"
let imgRef = storageReference.child(imagePath)
imgRef.getData(maxSize: 1 * 2048 * 2048) { data, error in
if let error = error {
print(String(describing: error))
}
else {
DispatchQueue.main.async {
let image = UIImage(data: data!)
imagesList.append(image!)
print("inside viewDidLoad: ", imagesList.count)
}
}
}
}
}
print(imagesList.count)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return imagesList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "imageCell", for: indexPath)
print("cellForRowAt: ",imagesList.count)
cell.textLabel?.text = "\(indexPath.row)"
cell.imageView?.image = imagesList[indexPath.row]
return cell
}
This is how my simulator looks like when I run the code: compiled code .
The code of my first UIViewController looks like this and basically I want to save the data whatever I type on the UITextField and retrieve it and populate on a UITableView. code as below. (I think my issue is in the cellForRow method)
import UIKit
import CoreData
class ViewController: UIViewController {
#IBOutlet weak var textField1: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func nxtbuttonpressed(_ sender: AnyObject) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
//Lets save data
let newUser = NSEntityDescription.insertNewObject(forEntityName: "Expenses", into: context)
newUser.setValue(textField1.text, forKey: "expenseName")
do {
try context.save ()
print("data saved successfully")
}catch{
print("There was an error")
}
performSegue(withIdentifier: "ShowNxtVC", sender: nil)
}
}
This is where I retrieve the data that I saved in the above VC (as the code bellow). However even though I can print all the data on the console, only the last data item I saved will populate to the UITableViewCell. How can i overcome this as to populate all the data that I've saved before instead the one that i saved last.
import UIKit
import CoreData
class TableViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var myArray : Array? = []
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest <NSFetchRequestResult> (entityName: "Expenses")
request.returnsObjectsAsFaults = false
do {
let results = try context.fetch(request)
// check data existance
if results.count>0 {
print(results.count)
for resultGot in results as! [NSManagedObject]{
if let expName = resultGot.value(forKey:"expenseName") as? String{
myArray = [expName]
print("my array is : \(myArray)")
}
}
}
}catch{
print("No Data to load")
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(myArray?.count)
return myArray!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell ()
cell.textLabel?.text = myArray? [indexPath.row] as! String?
return cell
}
}
first off all you have to change this:
myArray = [newValue] because that resets your array with just one value every time it finds a new expense in core data.
var array = [String]()
array = ["hello"]
array = ["joe"]
print(array)
// returns: ["joe"]
use:
myArray.append(newExpense)
and you get:
var array2 = [String]()
array2.append("hello")
array2.append("joe")
print(array2)
// returns: ["hello", "joe"]
After the FOR loop you add:
tableView.reloadData()
Now you should be up and running
There is another thing you should do:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExpCell", for: indexPath)
cell.textLabel?.text = myArray?[indexPath.row] as! String
return cell
}
In your Storyboard you need to put ExpCell as reuse identifier into the TableViewCell. The dequeReusableCell command loads only the cells you can see on your device and reuses those cells after you scrolled them out of sight. This way your app uses much less memory and will be faster.
update table view with data, after myArray = [expName] use
DispatchQueue.main.async { [unowned self] in
self.tableView.reloadData()
}
change the tableview cell for row at index path function that will solve your problem
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier identifier: String,
for indexPath: IndexPath)
if(!cell){
cell = tableView.register(tableViewCellClass,forCellReuseIdentifier identifier: String)
}
return cell
}
I am attempting to display data from Parse onto the following tableView controller. For some reason, the data is not displaying on the tableView (i.e. the rows are blank). I do not think that the data queried from Parse is being appended to the arrays. I am wondering what I'm doing wrong here.
Here's the current output:
I am using a custom prototype cell with identifier "CellTrack" class "TrackTableViewCell" and as shown below:
Here is my code in the TableViewController file:
import UIKit
import Parse
class MusicPlaylistTableViewController: UITableViewController {
var usernames = [String]()
var songs = [String]()
var dates = [String]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
var query = PFQuery(className:"PlaylistData")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects! as? [PFObject] {
self.usernames.removeAll()
self.songs.removeAll()
self.dates.removeAll()
for object in objects {
let username = object["username"] as? String
self.usernames.append(username!)
print("added username")
let track = object["song"] as? String
self.songs.append(track!)
let date = object["createdAt"] as? String
self.dates.append(date!)
self.tableView.reloadData()
}
}
} else {
print(error)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(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 usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.CreatedOn.text = dates[indexPath.row]
return cell
}
}
And here is my code in the "TrackTableViewCell.swift" class:
import UIKit
class TrackTableViewCell: UITableViewCell {
#IBOutlet weak var songTitle: UILabel!
#IBOutlet weak var username: UILabel!
#IBOutlet weak var CreatedOn: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Execute your tableView.reloadData() in main thread.
dispatch_async(dispatch_get_main_queue(), {
self.tableViewCell.reloadData()
})
Try doing a guard let to see if those values are actually coming back as string or not. My guess would be that the value for created at never came back. Try it out and let me know.
guard let username = object["username"] as? String else {
print ("could not get username")
}
self.usernames.append(username)
print("added username")
guard let track = object["song"] as? String else {
print ("could not get song")
return
}
self.songs.append(track)
guard let date = object["createdAt"] as? String else {
print ("could not get createdAt")
return}
self.dates.append(date!)
func dequeueReusableCellWithIdentifier(_ identifier: String) -> UITableViewCell?
Return Value
A UITableViewCell object with the associated identifier or nil if no such object exists in the reusable-cell queue.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
if cell == nil {
// create a new cell here
cell = TrackTableViewCell(...)
}
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.CreatedOn.text = dates[indexPath.row]
return cell
}
I am running into difficulty displaying the data from the query I made in the individual cells of my tableview. I believe that my logic is correct, but I'm not seeing the console.log's that I am calling within my function that contains the Parse queried data. This might be a simple fix, but it isn't coming to me at the moment. The console log I should be seeing to validate that my query is coming through correctly is the println("\(objects.count) users are listed"), it should then be displayed within the usernameLabel.text property.
import UIKit
class SearchUsersRegistrationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var userArray : NSMutableArray = []
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
loadParseData()
}
func loadParseData() {
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let objects = objects {
println("\(objects.count) users are listed")
for object in objects {
self.userArray.addObject(object)
}
self.tableView.reloadData()
}
} else {
println("There is an error")
}
}
}
let textCellIdentifier = "Cell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.userArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell
let row = indexPath.row
let cellDataParse : PFObject = self.userArray.objectAtIndex(row) as! PFObject
//cell.userImage.image = UIImage(named: usersArr[row])
cell.usernameLabel.text = cellDataParse.objectForKey("_User") as! String
return cell
}
}
I fixed the issue. I needed to cast the index path row in the users array as a PFUser and then cast the user's username property as a String and then set that as the label text.
let row = indexPath.row
var user = userArray[row] as! PFUser
var username = user.username as String
cell.usernameLabel.text = username
I am attempting to display the users image that is saved to parse property "image". I have been able to display my username with no issue, but I can't seem to be able to get my image to appear. Should I be casting this information as UIImage? Am I correctly calling where the file is stored?
Here is my code:
import UIKit
class SearchUsersRegistrationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var userArray : NSMutableArray = []
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
loadParseData()
var user = PFUser.currentUser()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadParseData() {
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let objects = objects {
println("\(objects.count) users are listed")
for object in objects {
self.userArray.addObject(object)
}
self.tableView.reloadData()
}
} else {
println("There is an error")
}
}
}
let textCellIdentifier = "Cell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.userArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell
let row = indexPath.row
var individualUser = userArray[row] as! PFUser
var username = individualUser.username as String
var profilePicture = individualUser["image"] as? UIImage
cell.userImage.image = profilePicture
cell.usernameLabel.text = username
return cell
}
#IBAction func finishAddingUsers(sender: AnyObject) {
self.performSegueWithIdentifier("finishAddingUsers", sender: self)
}
}
The photos are saved in a PFFile and not as a UIImage..
What makes your code the following:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell
let row = indexPath.row
var individualUser = userArray[row] as! PFUser
var username = individualUser.username as String
var pfimage = individualUser["image"] as! PFFile
pfimage.getDataInBackgroundWithBlock({
(result, error) in
cell.userImage.image = UIImage(data: result)
})
cell.usernameLabel.text = username
return cell
}
See more in the docs
fileprivate func getImage(withCell cell: UITableViewCell, withURL url: String) {
Alamofire.request(url).responseImage { (image) in
/* Assign parsed Image */
if let parsedImage = image.data {
DispatchQueue.main.async {
/* Assign Image */
cell.imageView?.image = UIImage(data: parsedImage)
/* Update Cell Content */
cell.setNeedsLayout()
cell.layoutIfNeeded()
}
}
}
}