Only one custom tableviewcell working correctly - swift

I created a custom tableviewcell with a photo and two labels. I queried some data from parse and the cells are suppposed to update the image and labels to reflect the query, however only the first viewcell works correctly. The image and labels work, however the second viewcell only displays the image correctly, the uilabels do not display any text. I've looked over the code multiple times and cant seem to figure out what i am doing wrong...
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("mySpotCell")/*, forIndexPath: indexPath)*/as? CustomTableViewCell
// cell = PFTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
if let value = mySpots[indexPath.row]["location"] {
let location = CLLocation(latitude: (value.latitude)!, longitude: (value.longitude)!)
self.geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemark, error) -> Void in
if error != nil {
print("error: \(error!.localizedDescription)")
}
if let pm: CLPlacemark = placemark![indexPath.row] {
// var pm = placemark![indexPath.row] as CLPlacemark
//self.parkingSpotAddress.text = pm.thoroughfare
// self.navigationController?.navigationBar.topItem?.title = pm.thoroughfare
//cell!.textLabel?.text = "\(pm.subThoroughfare!) \(pm.thoroughfare!)"
cell?.subtitleLabel.text = "\(pm.subThoroughfare!) \(pm.thoroughfare!)"
cell?.titleLabel.text = pm.description
print(cell?.subtitleLabel.text)
print(cell?.titleLabel.text)
}
})
if let parkingSpotImageFile: PFFile = mySpots[indexPath.row]["firstPhoto"] as! PFFile! {
parkingSpotImageFile.getDataInBackgroundWithBlock({ (imageData, error) -> Void in
if error == nil {
cell?.spotImageView.image = UIImage(data: imageData!)
// self.imageIndicator.stopAnimating()
// self.imageIndicator.hidden = true
}
})
}

I think you can check your func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int first. The value you return inside is the number of row it will show and load in tableview.
And my cellForRowAtIndex is like this, I think yours should be alright also. Just check the number of row in section.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:MenuTableViewCell = tbvMenu.dequeueReusableCellWithIdentifier("identifier") as! MenuTableViewCell
let temp:String = MenuArr[indexPath.row] as! String
cell.mainMenuTitle.text = temp
return cell
}

Related

How to properly display pictures in a TableView from Firebase Storage in SWIFT

I have a chat app where people can talk in a group and a little picture is displayed in each cell to show who is talking. I managed to display these pictures from Firebase storage but it is not always the right picture which is displayed at the right place.
It only works when I go to the previous View Controller and coming back the chat View to see the pictures displayed properly in each cell.
I tried to use DispatchQueue.main.async {} probably not in the good way cause it did not work for me.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let message = messageArray[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "customMessageCell", for: indexPath) as! CustomMessageCell
cell.selectionStyle = .none
// CHANGE TEXT ACCORDING TO SENDER
if message.sender == Auth.auth().currentUser?.email{
cell.messageBubble.backgroundColor = UIColor(red:0.30, green:0.68, blue:1.5, alpha:1.0)
// ...
} else {
cell.messageBubble.backgroundColor = UIColor(red:0.94, green:0.94, blue:0.94, alpha:1.0)
// ...
}
let theTimeStamp = messageArray[indexPath.row].createdAt
let doubleTime = Double(theTimeStamp)
let myDate = Date(timeIntervalSince1970: doubleTime )
let dateToShow = myDate.calenderTimeSinceNow()
cell.messageBodyTextView.text = messageArray[indexPath.row].messageBody
cell.usernameLabel.text = messageArray[indexPath.row].name
cell.timeLabel.text = dateToShow
let imagePath = self.storageRef.reference(withPath:"\(message.uid)/resizes/profilImage_150x150.jpg")
imagePath.getData(maxSize: 10 * 1024 * 1024) { (data, error) in
if let error = error {
cell.userPicture.image = UIImage(named: "emptyProfilPic")
cell.userPicture.layer.cornerRadius = cell.userPicture.frame.height / 2
cell.userPicture.clipsToBounds = true
print("Got an error fetching data : \(error.localizedDescription)")
return
}
if let data = data {
cell.userPicture.image = UIImage(data: data)
cell.userPicture.layer.cornerRadius = cell.userPicture.frame.height / 2
cell.userPicture.clipsToBounds = true
}
}
return cell
}
Thank you for your help !
You have to prepare the cell to be reusable with the proper override prepareForReuse().
For more clean code I suggest to you to implement the cells in separate cocoa Touch classes so it's easier to override and prepare for next data incoming, avoiding your problem.
What I mean it's a sort of this:
class mineCell:UITableViewCell {
#IBOutlet weak var text:UILabel!
#IBOutlet weak var img:UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
func updateCell(dataIn){
.
.
}
override func prepareForReuse() {
text.text = ""
img.image = nil
}
In your cellForRowAt table implementation just call the update function and pass your data like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "mineCell"
if let cell = mineTable.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as? mineCell {
updateCell(dataIn)
return cell
}
return mineCell()
}
In this way you are always sure that your cell will be ready for every reuse and not loading wrong data from the cell above.
Just to let you know, the problem was thaT I was reloading the table View after each message loaded. Instead, the best solution was to add a row to the tableview without reloaded the tableview after each message :
self.ConvertationTableView.insertRows(at: [IndexPath(row: self.messageArray.count - 1, section: 0)], with: .automatic)

How to set Image at current Cell (Kingfisher)? Swift

I have an TableView with custom cells. Label smiles contain links.
How can I put Image from link to current ImageView'cell? My code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "ClientCell"
self.cell = self.tableView.dequeueReusableCell(withIdentifier: identifier) as? customChatCell
let text = message[Constants.MessageFields.text] ?? ""
let selectedCell = self.tableView.cellForRow(at: indexPath) as? customChatCell
***
if text.range(of:"smiles") != nil {
let url = URL(string: text)
self.cell![indexPath.row].smile.kf.setImage(with: url)
}
***
}
not working. I'm getting error for line self.cell![indexPath.row].smile.kf.setImage(with: url)
Type 'customChatCell' has no subscript members
I'm using Kingfisher. If I use code
self.cell.smile.kf.setImage(with: url)
image putting into all cells, not for current.
Please help me fix it.
You should remove keeping the cell reference at class level. Your cellForRow should look like this,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "ClientCell"
let cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? customChatCell
let text = message[Constants.MessageFields.text] ?? ""
if text.range(of:"smiles") != nil {
let url = URL(string: text)
cell.smile.kf.setImage(with: url)
} else {
// Reset image to nil here if it has no url
cell.smile.image = nil
}
}
Remember, you are using a single UIView(i.e, customChatCell) for each cell in UITableView so when you dequeue a cell it's your responsibility to update/reset the UI elements according to your data for each cell.

How do I get the value from the model to the controller

This is my first program using MVC design pattern, I'm stuck how to get the values from the model to my controller and to display it in my view. I'll show you what I have done. Kindly clarify me what I did wrong? Or show me how it can be done in other way around.
Model
class songData: NSObject {
var artistName: String
var albumName: String
init(artistName: String, albumName: String) {
self.artistName = artistName
self.albumName = albumName
}
}
Controller
#IBAction func doTheSearch(sender: AnyObject) {
itunesAPI().itunesSearch({(song : songData) in
})
self.tableView.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return song1.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
var artistAndAlbum = itunesAPI().array[indexPath.row]
cell.textLabel?.text =
cell.detailTextLabel?.text =
return cell
}
API
func itunesSearch(completionHandler:(songData)->()) {
Alamofire.request(.GET, "http://itunes.apple.com/search?", parameters: ["term" : "tamil new songs", "media" : "music"])
.responseJSON { (response) in
let json = JSON(response.result.value!)
if let jsonData = json["results"].arrayObject {
self.array = jsonData as! [[String : AnyObject]]
if self.array.count > 0 {
// self.array = jsonData as! [[String : AnyObject]]
// if let resultsDict = resultsArray.first {
let albumName = json["results"]["collectionName"].stringValue
let artistName = json["results"]["artistName"].stringValue
let song = songData(artistName: artistName, albumName: albumName)
completionHandler(song)
}
}
I do have the nothing on my view except the story board which consists of a table view with a single cell. I need to get the response from the API and show it in the view.
First, you're going to want to reload your table after the data is returned. Update your IBAction to this:
itunesAPI().itunesSearch({(song : songData) in
self.tableView.reloadData()
})
Otherwise reloadData will get called before the data is returned. Set a property on the viewController to house the data. Also, it's good practice to start a class name with a capital letter.
var tableData:[SongData] = [SongData]()
Then set this variable when the data successfully returns:
itunesAPI().itunesSearch({(song : songData) in
self.tableData.append(song) // add the result to the list of data
self.tableView.reloadData() // reload the table
})
Then set the cells as so:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
var artistAndAlbum = self.tableData[indexPath.row]
cell.textLabel?.text = artistAndAlbum.artistName
cell.detailTextLabel?.text = artistAndAlbum.albumName
return cell
}

How to get the First Image from UICollectionViewCell and Save in UITableViewCell

I want to Save the First or the Last Image from the UICollectionView and Save it in the UITabelView Cell as UIImage.I try it with the first indexPath if indexPath == 0 catch the UIImage and then save it in CoreData as NSData but it doest works. Have anyone an idea how can i make that or gives another way to Display the UIImage in the UITableViewCell? Thanks for Help.
Here was the code from the UICollectionViewCell:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("BookPicCell", forIndexPath: indexPath) as! BookPicCell
let cellcore = picture[indexPath.row]
cell.BookImage.image = UIImage(contentsOfFile: cellcore.foto!)
if indexPath.row == 0 {
let firstpic = cell.BookImage.image
let firstcell = UIImagePNGRepresentation(firstpic!)
let firstimag = NSEntityDescription.insertNewObjectForEntityForName("Book", inManagedObjectContext: self.mgdContext) as! Book
firstimag.firstimage = firstcell!
}
do {
try self.mgdContext.save()
} catch {
print("Error")
}
return cell
}
Here was the Code from the UITableViewCell:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let Cell = BookTableView.dequeueReusableCellWithIdentifier("BookCell", forIndexPath: indexPath) as! BookCell
let books = book[indexPath.row]
Cell.BookTitle.text = books.title
let picturecount = books.picture!.count
Cell.BookImageCount.text = "\(picturecount) Picture"
let firstpicture = books.firstimage!
Cell.BookImage.image = UIImage(data: firstpicture)
return Cell
}

querying parse, how can I print the data within a tableView cell in Swift?

Hi guys I'm trying to print my query which Ive created in Parse, here it is
this works fine and does what i need it to
//store my currentLocations here
var locations : [PFObject] = []
PFGeoPoint.geoPointForCurrentLocationInBackground { (geoPoint:
PFGeoPoint?, error: NSError?) -> Void in
if geoPoint != nil {
var geoPointLon = geoPoint?.longitude
var geoPonitLan = geoPoint?.latitude
var currentLocation = PFGeoPoint(latitude: geoPonitLan!, longitude: geoPointLon!)
var query = PFQuery(className: "User")
query.whereKey("currentLocation", nearGeoPoint: currentLocation, withinKilometers: 5.0)
query.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
if let myObject = objects as? [PFObject] {
for objects in myObject {
self.locations.append(objects)
}
}
self.tableView.reloadData()
})
}
}
this is my tableview cell and number of rows
func tableView(tableView: UITableView, numberOfRowsInSection section:
Int) -> Int {
return self.locations.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "test"
return cell
}
when running my app "test" does print the correct number of entries so I know my query is working.
My question is how can I print the actual locations from my class "User", column named "currentLocation" within Parse?
if you need any other info just let me know thanks
Assuming your "currentLocation" column is a string, that's how you get it back.
if it is not a string, then you might need to convert it.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = self.locations["currentLocation"]
return cell
}