UIImageView in cell not showing image - ios

So I have a table view and an array named offlineImages that contain images stored in the Documents folder. I want this images to show in the image view of the cells. The code compiles, but does not show the image. The URLs stored, the cell identifier and the tag are correct.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "offlineCell")
let mainImageView = cell?.viewWithTag(2) as! UIImageView
let mainImageURL = offlineImages[indexPath.row]
let mainImageData = NSData(contentsOf: mainImageURL)
let mainImage = UIImage(data: mainImageData! as Data)
mainImageView.image = mainImage
return cell!
}
Here is how I have downloaded the images:
let imageDestination: DownloadRequest.DownloadFileDestination = { _, _ in
var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
documentsURL.appendPathComponent("image."+"png")
return (documentsURL, [.removePreviousFile])
}
Alamofire.download(mainImageURL, to: imageDestination).response { response in
if response.destinationURL != nil {
finalImageURL = response.destinationURL!
}
}

pbb you didn't save the pics correctly. Check that.

Solved it:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "offlineCell")
let mainImageView = cell?.viewWithTag(2) as! UIImageView
let mainImageURL = offlineImages[indexPath.row]
let mainImageData = NSData(contentsOf: mainImageURL)
let mainImage = UIImage(data: mainImageData! as Data)
if let image1 = mainImage {
mainImageView.image = image1
}
return cell!
}

Related

dynamic image resizing after asynchronously downloading it from the firebase

I am trying to dynamically adjust the image size depending upon the image that I download from the firebase database and present it in the table view cell. I want the width of the image to be the frame width and the height to adjust accordingly.
I have a customImageView class to download image asynchronously from firebase
I've tried many methods but in vain. Is there a super clean way to adjust the image size dynamically :-D
this Is my cell :
class viewControllerHomeCell: UITableViewCell {
#IBOutlet var mainImage: CstmImageView!
}
my cell for row at :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellData = TableViewControllerHome.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! viewControllerHomeCell
cellData.mainImage.loadImagesWithUrl(from: self.postArray[indexPath.row].covrImgUrl)
}
and this is a UIImageView subclass to load images from the firebase async. :
class CstmImageView : UIImageView {
let imageCache = NSCache<AnyObject, AnyObject>()
var imageUrlString : String?
func loadImagesWithUrl(from imageUrl : String!) {
imageUrlString = imageUrl
self.image = nil
if let cachedImage = imageCache.object(forKey: imageUrl as AnyObject) as? UIImage {
self.image = cachedImage
return
}
let url = URLRequest(url: URL(string: imageUrl)!)
URLSession.shared.dataTask(with: url) { (data, response, eror) in
if eror != nil {
print(eror!)
return
}
DispatchQueue.main.async {
if let downloadedImage = UIImage(data : data!) {
if self.imageUrlString == imageUrl {
self.image = downloadedImage
}
self.imageCache.setObject(downloadedImage, forKey: imageUrl as AnyObject)
}
}
}.resume()
}
}
any help is appreciated a a lot : )
Take your imageView Height Outlet and connect with your imageView height constrain
class viewControllerHomeCell: UITableViewCell {
#IBOutlet var mainImage: UIImageView!
#IBOutlet var viewImageViewHeight: NSLayoutConstraint!
}
And Use Pod for Download Image
pod 'SDWebImage'
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cellData = TableViewControllerHome.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! viewControllerHomeCell
cellData.mainImage.sd_setImage(with:URL.init(string: "Pass Yor image Url string here"))
{ (image, error, imageCacheType, url) in
cellData.mainImage.image = image
viewImageViewHeight.constant = image?.size.height
}
cellData.mainImage.loadImagesWithUrl(from: self.postArray[indexPath.row].covrImgUrl)
}

Stack spacing is ignored

I've an image which is downloaded async. This image is resized to fit the screen by a constraint. This seems to break the vertical spacing between the image and label in the table cell which is set by the stack view.
Table view
xCode constrains
Result iPhone 5S
Code to set the image height:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "overview", for: indexPath) as! OverviewCell
let upload = images[indexPath.row]
cell.titleLabel.text = upload.image.title
let cachedImage = cachedImages[upload.image.imageUrl]
if let cachedImage = cachedImage {
var cellFrame = cell.frame.size
cellFrame.width = cellFrame.width - 30
let resizedImage = cachedImage.resize(width: cellFrame.width)
cell.imageView!.image = resizedImage
cell.heightConstrain.constant = resizedImage.size.height
}
else {
DispatchQueue.global().async {
let data = try! Data.init(contentsOf: URL.init(string: upload.image.imageUrl)!)
DispatchQueue.main.sync {
self.cachedImages[upload.image.imageUrl] = UIImage.init(data:data)!
self.tableView.beginUpdates()
self.tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.fade)
self.tableView.endUpdates()
}
}
}

Returns nil if I scroll tableView fast

Trying to load images in tableView asynchronously in (Xcode 9 and Swift 4) and seems I have a correct way but my code stops working if I scroll my tableView fast. So basically I had found nil error.
Here is my code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
let feed = feeds[indexPath.row]
cell.titleLabel.text = feed.title
cell.pubDateLabel.text = feed.date
cell.thumbnailImageView.image = nil
if let image = cache.object(forKey: indexPath.row as AnyObject) as? UIImage {
cell.thumbnailImageView?.image = image
} else {
let imageStringURL = feed.imageUrl
guard let url = URL(string: imageStringURL) else { fatalError("there is no correct url") }
URLSession.shared.downloadTask(with: url, completionHandler: { (url, response, error) in
if let data = try? Data(contentsOf: url!) {
DispatchQueue.main.async(execute: {
guard let image = UIImage(data: data) else { fatalError("can't create image") }
let updateCell = tableView.cellForRow(at: indexPath) as! CustomTableViewCell // fast scroll issue line
updateCell.thumbnailImageView.image = image
self.cache.setObject(image, forKey: indexPath.row as AnyObject)
})
}
}).resume()
}
return cell
}
I have issue on the line:
let updateCell = tableView.cellForRow(at: indexPath) as! CustomTableViewCell
If I scroll down slowly everything works just fine and no mistakes appear.
Does anyone know where I've made a mistake?
This may happens if cell you are trying to get using tableView.cellForRow(at:) is not visible currently.
To avoid crash you can use optionals as:
let updateCell = tableView.cellForRow(at: indexPath) as? CustomTableViewCell // fast scroll issue line
updateCell?.thumbnailImageView.image = image
Keep everything as it is, I hope it should work without any errors.
You can consider one of popular UIImage extension libs, like I said in comment for example AlamofireImage and set thumbnail with the placeholder, as soon as image will be ready it will be replaced automatically.
One more thing I change no need to have updateCell I removed it.
Please add placeholder image and test it should work, sorry I didn't fully check syntax.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
let feed = feeds[indexPath.row]
if let image = cache.object(forKey: indexPath.row as AnyObject) as? UIImage {
cell.thumbnailImageView?.image = image
} else {
let imageStringURL = feed.imageUrl
guard let url = URL(string: imageStringURL) else { fatalError("there is no correct url") }
cell.thumbnailImageView.af_setImage(withURL : url, placeholderImage: <your_placeholderImage>)
return cell
}

How to load an image from URL and display it in tableView cell (Swift 3)

I have the image URL and I want to display that image in UIImageView which is placed in a tableView cell.
I created a custom cell and added an outlet for the imageView.
Since I am loading news the URL changes accordingly.
NOTE: I am using Alamofire to process my HTTP requests.
struct News {
let title: String
let text: String
let link: String
let imgUrl: String
init(dictionary: [String:String]) {
self.title = dictionary["title"] ?? ""
self.text = dictionary["text"] ?? ""
self.link = dictionary["link"] ?? ""
self.imgUrl = dictionary["imgUrl"] ?? ""
}
}
And loading info to my custom cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? newsCellTableViewCell
let news = newsData[indexPath.row]
cell?.headline.text = news.title
cell?.excerpt.text = news.text
cell?.thumbnailImage.text = news.imgUrl
return cell!
}
You can use this code to get image from url and can set a placeholder image as well. for example:-
cell.imageView?.imageFromURL(urlString: "urlString", PlaceHolderImage: UIImage.init(named: "imagename")!)
extension UIImageView {
public func imageFromServerURL(urlString: String, PlaceHolderImage:UIImage) {
if self.image == nil{
self.image = PlaceHolderImage
}
URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error ?? "No Error")
return
}
DispatchQueue.main.async(execute: { () -> Void in
let image = UIImage(data: data!)
self.image = image
})
}).resume()
}}
This becomes quite easy, as you're using Alamofire. Unlike #Mochi's example, this won't block the interface.
Here's an example:
Alamofire.request(news.imgUrl).response { response in
if let data = response.data {
let image = UIImage(data: data)
cell?.thumbnailImage.image = image
} else {
print("Data is nil. I don't know what to do :(")
}
}
*Please note I wasn't able to test this before I answered. You may need to tweak this code a bit.
I used a Kingfisher library
import Kingfisher
tableViewCell class:
class MyCell: UITableViewCell {
#IBOutlet weak var cellImg: UIImageView!
#IBOutlet weak var cellLbl: UILabel!
}
Assign this class to your cell in storyboard
And finally, do this in CellForRowAt
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell")! as! MyCell
let url = URL(string: "https://files.pitchbook.com/website/files/jpg/food_delivery_800.jpg")
cell.cellImg.kf.setImage(with: url)
return cell
}
That's it
Please Use SDWebImage. It's an imageview category that downloads the image in the background without freezing your UI, and also provides caching as well. You can set a placeholder image as well. Placeholders show until your actual image is downloaded. After downloading, the actual image in your cell's Imageview is updated automatically, and you don't need to use any completion handler.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? newsCellTableViewCell
let news = newsData[indexPath.row]
cell?.headline.text = news.title
cell?.excerpt.text = news.text
cell?.thumbnailImage.sd_setImageWithURL(NSURL(string: news.imgUrl), placeholderImage:UIImage(imageNamed:"placeholder.png"))
return cell!
}

UIImage overlaps labels if it's set to .scaleAspectFill

My app loads images from a backend and displays them in a UITableViewCell, that contains a UIImageView to display it and some labels and buttons.
I've added the suggested contraints to the UITableViewCell with the 'Reset to suggested contraints' option.
Here's some of the code after retrieving the data:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = PostTableViewCell()
if (self.posts.count == 0) { return cell }
let post = posts[indexPath.row]
// Instancia o reuse identifier
if post["post_image"] != nil {
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage, for: indexPath) as! PostTableViewCell
} else {
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithoutImage, for: indexPath) as! PostTableViewCell
}
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var cell = PostTableViewCell()
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage) as! PostTableViewCell
return cell.bounds.size.height;
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var cell = PostTableViewCell()
cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.PostWithImage) as! PostTableViewCell
return cell.bounds.size.height;
}
private func configureCell(cell: PostTableViewCell, atIndexPath indexPath: IndexPath) {
cell.queue.cancelAllOperations()
let operation: BlockOperation = BlockOperation()
operation.addExecutionBlock { [weak operation] () -> Void in
DispatchQueue.main.sync(execute: { [weak operation] () -> Void in
if (operation?.isCancelled)! { return }
let post = self.posts[indexPath.row]
cell.accessibilityIdentifier = post.recordID.recordName
guard let postTitle = post["post_title"], let postBody = post["post_body"] else {
return
}
if let asset = post["post_image"] as? CKAsset {
self.imageCache.queryDiskCache(forKey: post.recordID.recordName, done: { (image, cachetype) in
if image != nil {
cell.postImageView.contentMode = .scaleAspectFill
cell.postImageView.autoresizingMask = [.flexibleBottomMargin,
.flexibleHeight,
.flexibleLeftMargin,
.flexibleRightMargin,
.flexibleTopMargin,
.flexibleWidth ];
cell.postImageView.image = image!
} else {
do {
let data = try Data(contentsOf: asset.fileURL)
let image = UIImage(data: data)
cell.postImageView.contentMode = .scaleAspectFill
cell.postImageView.autoresizingMask = [.flexibleBottomMargin,
.flexibleHeight,
.flexibleLeftMargin,
.flexibleRightMargin,
.flexibleTopMargin,
.flexibleWidth ];
cell.postImageView.image = image!
self.imageCache.store(image!, forKey: post.recordID.recordName)
} catch {
print("Error 1001 = \(error.localizedDescription)")
}
}
})
}
cell.titleLabel.text = postTitle as? String
cell.bodyLabel.text = postBody as? String
})
}
cell.queue.addOperation(operation)
}
Here's some prints from the app itself that shows the image overlapping over the labels.
It only overlaps if the image is in portrait mode, if the image was taken in landscape it suits well.
What's the best way to bypass this issue?
You can programmatically tell the image to draw only in the given image area. If your constraints are working properly and it is staying the correct size, the image may just be drawing beyond the View bounds because of the .scaleAscpedtFill setting.
Do this by using .clipToBounds = true.
cell.postImageView.clipToBounds = true
Or, you can set it in interface builder as well, per the image below.
Give that a try and see if that helps?

Resources