How to set Image at current Cell (Kingfisher)? Swift - 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.

Related

how to get the value of a label placed on table view cell

I have a number of cells in my tableview each containing different label values
when i tap on the cell I want that value of label in next view controller. how do I get that?
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as!
MeetingsListTableViewCell
if self.meeting.count > 0{
let eachMeeting = self.meeting[indexPath.row]
cell.meetingTimeLabel?.text = (eachMeeting["time"] as? String) ?? "No Time"
cell.meetingDateLabel?.text = (eachMeeting["date"] as? String) ?? "No Date"
cell.idLabel?.text = (eachMeeting["id"] as? String) ?? "NO ID"
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = UIStoryboard.init(name: "Main4", bundle:Bundle.main).instantiateViewController(withIdentifier: "MeetingDetailVC") as? MeetingDetailVC
self.navigationController?.pushViewController(vc!, animated: true)
}
i want that idLabel value to send in the next viewcontroller
Get the data always from the data source array meeting, never from the cell, for example
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let aMeeting = self.meeting[indexPath.row]
let identifier = aMeeting["id"] as! String
guard let vc = UIStoryboard.init(name: "Main4", bundle:Bundle.main).instantiateViewController(withIdentifier: "MeetingDetailVC") as? MeetingDetailVC else { return }
vc.identifier = identifier
self.navigationController?.pushViewController(vc, animated: true)
}
The code assumes that there is a property identifier in MeetingDetailVC
Notes:
For better readability you should name arrays in plural form (meetings).
The check self.meeting.count > 0 is pointless, cellForRowAt is not being called if the data source array is empty.
It's highly recommended to use a custom struct as data source rather than an array of dictionaries. You will get rid of all those annoying type casts.
Tapped cell can be accessed in didSelectRowAt function of tableVeiw. Extract tableView cell and cast int into your custom cell, after casting you can directly access value of lableId, add an optional property in MeetingDetailVC and pass value to it.

Fetching from Core Data and display in UITableView with custom cell

I have a UITableView with a custom cell:
title, label, text
These are 3 elements of UITextView, now I have an entity in my core data:
I want to put title, in title, the date in label and introText in text:
I did this:
do{
var request = NSFetchRequest<NSFetchRequestResult>(entityName: "Actualites")
let count = try context.count(for: request)
if (count == 0) {
REST().SaveArticles(limit: 5, limitstart: 0, catid: 6, key: "xxx", context: context)
} else {
var actualites = [Actualites]()
actualites = try context.fetch(request) as! [Actualites]
let cell:ActuTblCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! ActuTblCell
for actualites in actualites {
print(actualites.title)
}
}
}catch{
print(error)
}
I can get the titles in the loop, but how to display the data ? Do I have to create 3 arrays ?
EDIT:
I think I have to do a loop here ?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ActuTblCell
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy HH:mm"
cell.titleActuCell.text = actualites[indexPath.row].title
cell.dateActuCell.text = formatter.string(from: actualites[indexPath.row].created! as Date)
cell.descriptionActuCell.text = actualites[indexPath.row].introText
return cell
}
Thread 1: Fatal error: Index out of range
In your view controller keep an array of Actualites: var actualites = [Actualites](). Then your else block would look like this:
else {
actualites = try context.fetch(request) as! [Actualites]
tableview.reloadData()
}
You should implement the UITableViewDataSource protocol to return the number of cells based on the actualites array, and in the tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) you get the actuality for every cell by this statement: let actuality = actualites[indexPath.row] and display in the appropriate cell.

Swift 3 Breaks Cell For Row At Index Path

This code was from a now inactive tutorial that helped me load in data to a table view. Since the tutorial was written in Swift 2.0, I believe that this was changed in Swift 3. I know that the override function itself was changed, which I handled. But now, it brings me a Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP, subcode=0x0) error.
Update: I have tried multiple things including creating a custom class for the cell. I still either get the same error I listed above, or a Thread 1: Signal SIGABRT error on the first line of my App Delegate file. Creating a breakpoint hasn't helped me because I know where the error is coming from.
import UIKit
import Firebase
import FirebaseDatabase
struct postStruct {
let title : String!
let message : String!
}
class LoggedInController: UITableViewController {
var posts = [postStruct]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Posts").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let title = snapshotValue!["title"] as? String
let message = snapshotValue!["message"] as? String
self.posts.insert(postStruct(title: title, message: message), at: 0)
self.tableView.reloadData()
})
post()
}
func post(){
let title = "Title"
let message = "Message"
let post : [String : AnyObject] = ["title" : title as AnyObject,
"message": message as AnyObject]
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Posts").childByAutoId().setValue(post)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].message
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].message
return cell!
}
}
Update 2: Here is the new code I used. It's not pretty and only gets the title.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell?.textLabel?.text = posts[indexPath.row].title
cell?.detailTextLabel?.text = posts[indexPath.row].message
return cell!
} else {
let label1 = cell?.viewWithTag(1) as? UILabel
label1?.text = posts[indexPath.row].title
let label2 = cell?.viewWithTag(2) as? UILabel
label2?.text = posts[indexPath.row].message
return cell!
}
}
Using dequeueReusableCell, you are accessing cell which doesn't exists. To make your code work change the below line:
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
To
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
Ok this code let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") produces an optional called cell that may or may not contain a a valid instance of UITableViewCell. Optionals in Swift are a way to safeguard against nil values, you can read more about optionals here: Optionals
On the first run when your table view wants to load its data it calls all the required methods of your UITableViewDataSource. The first run is a critical one because there aren't any instances of the UITableViewCell the table view can dequeue yet. To solve your problem you have to do something similar to the code below:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell?.textLabel?.text = "New value"
cell?.detailTextLabel?.text = "New value"
return cell!
} else {
cell?.textLabel?.text = "" //reset value
cell?.detailTextLabel?.text = "" // resetValue
cell?.textLabel?.text = "New value"
cell?.detailTextLabel?.text = "New value"
return cell!
}
}
Code similar to the one above are usually used to programmatically add an instance of UITableViewCell. However, if you used interface builder to add a prototype cell use the let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) method to dequeue your cells in which case it does not return an optional and you do not need to do all the if / else blocks.
Something else I wanted to mention about your code is finding sub views buy their ID will not produce a very object oriented code and that maybe the source of your errors where the compiler can not find the sub views. The better way would be to use one of the built in instances of UITableViewCell such as .default or alliteratively you could subclass the said class and make your very own custom cells.
Hope this helped!
Try this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].message
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].message
return cell
}
Edited
Make Sure you did these things
UITableViewController
In viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier:"catCell" )
let catNib : UINib = UINib.init(nibName: "TableViewCategoryCell", bundle: nil)
self.tableView.register(catNib, forCellReuseIdentifier: "TableViewCategoryCell")
In cellForRowAt indexPath
let cell : OPM_AlarmTableViewCategoryCell = tableView.dequeueReusableCell(withIdentifier:"OPM_AlarmTableViewCategoryCell" ) as! OPM_AlarmTableViewCategoryCell!
cell.categoryLabel?.text = "Some Text"
return cell
UITableviewCell.XIB
Hope u did these things
UITableviewCell
Make sure the dot appears so that the #IBOutlet is connected with the
xib label

Only one custom tableviewcell working correctly

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
}

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
}