func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = chatableView.dequeueReusableCell(withIdentifier: "SendMsgCell", for: indexPath) as! SendMsgTableViewCell
let msg = chatList[indexPath.row]
if msg.emoURL != nil{
cell.sticonFrame.kf.setImage(with: getEmojiFromURL(msg.emoURL!),completionHandler:{
(image, error, cacheType, imageUrl) in
if image != nil{
cell.sticonFrame.alpha = 1
}else{
cell.sticonFrame.alpha = 0
cell.sticonFrame.image = nil
}
})
cell.layoutIfNeeded()
}else{
cell.sticonFrame.alpha = 0
cell.sticonFrame.image = nil
}
return cell
}
KingFisher can't load First view
First scroll down can't see image
if want see image You have to come down after scroll up
layoutIfNeeded is not solved i haven't idea
Will see it dynamic after Once call image,
I don't think there is some error please check your URL is not empty and maybe image size is big.
//go for this appoarch
class INSUtilities {
class func setImage(onImageView image:UIImageView,withImageUrl imageUrl:String?,placeHolderImage: UIImage) {
if let imgurl = imageUrl{
image.kf.indicatorType = IndicatorType.activity
image.kf.setImage(with: URL(string: imgurl), placeholder: placeHolderImage, options: nil, progressBlock: nil, completionHandler: { (image, error, cacheType, url) in
})
}
else{
image.image = placeHolderImage
}
}
}
//incellclass call like this
//logoImg is the name of imageView
INSUtilities.setImage(onImageView: cell.sticonFrame, withImageUrl: logo!, placeHolderImage: #imageLiteral(resourceName: "pic_PlaceHolder"))
Related
My images take a second to load before they appear, which looks bad. On apps such as instagram, the tableview is hidden until the tableview is loaded... how do they do this? I have a loader that I want to display but don't know when to stop it and show tableview and detect the images have first finished loading? Where do I put stopTimer() ?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell",
for: indexPath) as! MainTableViewCell
let payment = self.payments[indexPath.row]
cell.profilePicture.layer.cornerRadius = cell.profilePicture.frame.size.width / 2
cell.profilePicture.clipsToBounds = true
if let profileImageUrl = payment.picture {
cell.profilePicture.loadImageUsingCacheWithUrlString(profileImageUrl)
}
if payment.message == "none" {
cell.detailsLabel.text = "No Message"
} else {
cell.detailsLabel.text = "\"\(payment.message ?? "")\""
}
}
MY CODE TO FETCH IMAGE IN TABLEVIEW:
let imageCache = NSCache<NSString, AnyObject>()
extension UIImageView {
func loadImageUsingCacheWithUrlString(_ urlString: String) {
self.image = nil
//check cache for image first
if let cachedImage = imageCache.object(forKey: urlString as NSString) as? UIImage {
self.image = cachedImage
return
}
//otherwise fire off a new download
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
//download hit an error so lets return out
if let error = error {
print(error)
return
}
DispatchQueue.main.async(execute: {
if let downloadedImage = UIImage(data: data!) {
imageCache.setObject(downloadedImage, forKey: urlString as NSString)
self.image = downloadedImage
}
})
}).resume()
}
}
You can simple use SDWebImage with cocoaPods and use it for async image downloader with cache support. Your cell will look like after ad SDWebImage.
import SDWebImage
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell",
for: indexPath) as! MainTableViewCell
let payment = self.payments[indexPath.row]
cell.profilePicture.layer.cornerRadius = cell.profilePicture.frame.size.width / 2
cell.profilePicture.clipsToBounds = true
if let profileImageUrl = payment.picture {
cell.profilePicture.sd_setImage(with: profileImageUrl, placeholderImage: UIImage(named: "yourPlaceholderImage.png"))
}
if payment.message == "none" {
cell.detailsLabel.text = "No Message"
} else {
cell.detailsLabel.text = "\"\(payment.message ?? "")\""
}
}
There is no need to hide tableView for downloading image.
I have a tableview that displays data from Firebase. It displays fine in the tableview but when scrolling begins, the table starts glitching or having the cells image and text reload and flicker which is very ugly. Help! Here's my code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell", for: indexPath) as! MainTableViewCell
func downloadPicture(finished: () -> Void) {
cell.profilePicture.image = nil
if let imageUrlString = self.payments[indexPath.row].picture,
let imageUrl = URL(string: imageUrlString) {
do {
let imageData = try Data(contentsOf: imageUrl)
cell.profilePicture.image = UIImage(data: imageData)
cell.profilePicture.layer.cornerRadius = cell.profilePicture.frame.size.width / 2
cell.profilePicture.clipsToBounds = true
cell.profilePicture.alpha = 1
}
catch {
print("Error fetching image - \(error)")
}
}
finished()
}
downloadPicture {
print("success")
}
cell.amountLabel.text = "$\(self.payments[indexPath.row].amount ?? "")"
cell.detailsLabel.text = self.payments[indexPath.row].amount ?? ""
return cell
}
You can simply go with SDWebImage An asynchronous image downloader with cache management and efficient to use.
i.e. :
import SDWebImage
yourImageView.sd_setImage(with: URL(string: "yourImageURLFromFirebase.jpg"), placeholderImage: UIImage(named: "placeholder.png"))
#Lukeksaunders just go to GitHub Kinfisher. This library contains all functionality you want.
import Kingfisher
let url = URL(string: "https://example.com/image.png")
imageView.kf.setImage(with: url)
This library cache your images
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell", for: indexPath) as! MainTableViewCell
if let imageUrlString = self.payments[indexPath.row].picture,
let imageUrl = URL(string: imageUrlString) {
cell.profilePicture.kf.setImage(with: imageUrl)
}
cell.amountLabel.text = "$\(self.payments[indexPath.row].amount ?? "")"
cell.detailsLabel.text = self.payments[indexPath.row].amount ?? ""
return cell
}
I made a chat app. When I chatting and post image message to A man. I check my image upload successful,and download to local document failed. A man's view just have imageView with clear background.No image to show,and I click back to previous view,then go back chat view. The image show up. what's happen? how to let image download to local immediatly? Thanks!!
This is my download function code:
func ImageFromUrl(imageView:UIImageView,url:String) {
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(Image)/")
let fileName = url + ".jpg"
let fileURL = documentsDirectoryURL.appendingPathComponent(fileName)
let urlString = URL(string: url)
if let image = UIImage(contentsOfFile: fileURL.path)
{
imageView.image = image
return
}
DispatchQueue.global().async {
let data = try? Data(contentsOf: urlString!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
if data != nil
{
if let image = UIImage(data: data!)
{
if !FileManager.default.fileExists(atPath: fileURL.path) {
if let jpegData = UIImageJPEGRepresentation(image, 0.001)
{
do {
try jpegData.write(to: fileURL, options: .atomic)
} catch {
debug(object: error)
}
}
} else {
debug(object:"file already exists")
}
DispatchQueue.main.async {
imageView.image = image//UIImage(data: data!)
}
}
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomTableViewCell = CustomTableViewCell(style: .default, reuseIdentifier: nil)
if cell.isRight == false { //A man's cell View
ImageFromUrl(imageView:cell.imageView,url:imageUrl)
//tableView.reloadRow(at:indexPath, with: .automatic)
//tableView.reloadRows(at: [indexPath], with: .automatic)
//tableView.reloadRow(UInt(contents.count-1), inSection: 0, with: .automatic)
}
}
Since this is being pushed to GCD the table will finish updating while the image is loaded. Therefore you will need reload the data in the table view.
Change:
DispatchQueue.main.async {
imageView.image = image//UIImage(data: data!)
}
to:
DispatchQueue.main.async {
imageView.image = image//UIImage(data: data!)
self.tableView?.reloadData()
}
But this won't be enough, as the image will be recreated each time tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell is called and you will be caught in an infinite loop. I would recommend subclassing UITableViewCell to create your own cell that contains an image property. Then you can tell ImageFromURL(_) to save the image to the cell's image property, and then reload the view.
I have a UICollectionViewCell and Inside that there is a imageView. My requirement is that I am getting Images Url from My_API and I want to download the Images from these Images Url and want to show them into a collectionViewCell imageView.
First thing is that how can I download the images from url I mean Which method is best and how to use NSCache in CollectionViewCell for images (in CellForRowAtIndexPath method).
Here is my code:
//MARK : DataSource
extension BrandImagesTableCell : UICollectionViewDataSource,UICollectionViewDelegateFlowLayout
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if 0 != arrImages.count {
return self.arrImages.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BrandImagesCell", for: indexPath) as! BrandImagesCell
//let StrUrl = NSURL(string: self.arrImages[indexPath.row])! as URL
let urlPath: String = self.arrImages[indexPath.row]
let StrUrl: NSURL = NSURL(string: urlPath)!
if 0 != arrImages.count
{
cell.brandImage.downloadedFrom(url: StrUrl as URL)//, contentMode: .scaleToFill)
//cell.backgroundColor = UIColor.lightGray
}
return cell
}
}
In self.arrImages I have Images url.
And here is my download image method:
//Download Image from server.
extension UIImageView {
func downloadedFrom(url: URL) { //, contentMode mode: UIViewContentMode = .scaleAspectFit) {
//contentMode = mode
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { () -> Void in
self.image = image
}
}.resume()
}
}
So I want to know which method is better to download images, and do I have to use thread or NSCache?
Use KingFisher download this library and add into your project.
Use code like :
let ProfileUrl = YOUR_URL! as! String
if ProfileUrl.isEmpty == true {
YOURIMAGE_VIEW.image = UIImage.init(named: "ic_default_IMAGE.png")
}else{
let fbUrl = NSURL(string: ProfileUrl )!
YOURIMAGE_VIEW.kf_setImageWithURL(fbUrl, placeholderImage: nil,
optionsInfo: [.Transition(ImageTransition.Fade(1))],
progressBlock: { receivedSize, totalSize in
},
completionHandler: { image, error, cacheType, imageURL in
print("Finished")
})
}
Retrive image from cache file
KingfisherManager.sharedManager.retrieveImageWithURL(url, optionsInfo: nil, progressBlock: nil, completionHandler: { (image, error, cacheType, imageURL) -> () in
print(image)
})
Using Swift 3 :-
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BrandImagesCell", for: indexPath) as! BrandImagesCell
//let StrUrl = NSURL(string: self.arrImages[indexPath.row])! as URL
let urlPath: String = self.arrImages[indexPath.row]
//let StrUrl: NSURL = NSURL(string: urlPath)!
if 0 != arrImages.count
{
let imgUrl = urlPath
//Add Default image
if imgUrl.isEmpty == true {
cell.brandImage.image = UIImage.init(named: "placeholder.png")
}
else
{
let url = URL(string: imgUrl)!
cell.brandImage.kf.setImage(with: url,
placeholder: nil,
options: [.transition(.fade(0.5))],
progressBlock: { receivedSize, totalSize in
print("\(indexPath.row + 1): \(receivedSize)/\(totalSize)")
},
completionHandler: { image, error, cacheType, imageURL in
print("Finished")
//print("\(indexPath.row + 1): Finished")
})
}
}
return cell
}
I am grabbing my images from my server, grabbing the URL from my database, and displaying it inside my custom tableview cell.
I'm using the extension below to convert URL into images. As you can see it is fetching the images asynchronously, but it doesn't show the image. I checked the URL is valid, but it's not displaying
After I've fetched my data using NSJSONSerialization, I did a
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
This is how I call it in my cellForRowAtIndexPath
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:LatestPostCustomTableViewCell = tableView.dequeueReusableCellWithIdentifier("LatestPostCustomTableViewCell", forIndexPath: indexPath) as! LatestPostCustomTableViewCell
cell.imagePost.downloadedFrom(link: latestPost[indexPath.row].imageURL, contentMode: .ScaleAspectFit)
return cell
}
}
The extension that I'm using retrieved from Loading/Downloading image from URL on Swift
extension UIImageView {
func downloadedFrom(link link:String, contentMode mode: UIViewContentMode) {
guard
let url = NSURL(string: link)
else {return}
contentMode = mode
NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
guard
let httpURLResponse = response as? NSHTTPURLResponse where httpURLResponse.statusCode == 200,
let mimeType = response?.MIMEType where mimeType.hasPrefix("image"),
let data = data where error == nil,
let image = UIImage(data: data)
else { return }
dispatch_async(dispatch_get_main_queue()) { () -> Void in
self.image = image
}
}).resume()
}
}