how to implement lazy loading of images in table view using swift

后端 未结 3 911
刺人心
刺人心 2020-11-29 00:13

I want to use lazy loading concept for my table view using swift. In my table view i am showing multiple cells which contain product images and product name . Please help me

相关标签:
3条回答
  • 2020-11-29 00:24

    Since I can't comment just yet, here's a Swift 3 (Xcode 8 Beta 6) version of the useful extension provided by Leo Dabus.

    extension UIImageView {
        func downloadImageFrom(link:String, contentMode: UIViewContentMode) {
            URLSession.shared.dataTask( with: NSURL(string:link)! as URL, completionHandler: {
                (data, response, error) -> Void in
                DispatchQueue.main.async {
                    self.contentMode =  contentMode
                    if let data = data { self.image = UIImage(data: data) }
                }
            }).resume()
        }
    }
    

    I'm using this inside a class that populates the table cell, it works like this in that context just fine, just in case any newbs were wondering if it will:

    albumArt.image = UIImage(named: "placeholder")
    albumArt.downloadImageFrom(link: "http://someurl.com/image.jpg", contentMode: UIViewContentMode.scaleAspectFit)
    
    0 讨论(0)
  • 2020-11-29 00:30

    Old Solution:

    Since you doesn't show any code.

    Here is the example for you.

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
        // try to reuse cell
        let cell:CustomCell = tableView.dequeueReusableCellWithIdentifier("DealCell") as CustomCell
    
        // get the deal image
        let currentImage = deals[indexPath.row].imageID
        let unwrappedImage = currentImage
        var image = self.imageCache[unwrappedImage]
        let imageUrl = NSURL(string: "http://staging.api.cheapeat.com.au/deals/\(unwrappedImage)/photo")
    
        // reset reused cell image to placeholder
        cell.dealImage.image = UIImage(named: "placeholder")
    
        // async image
        if image == nil {
    
        let request: NSURLRequest = NSURLRequest(URL: imageUrl!)
    
        NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
            if error == nil {
    
                image = UIImage(data: data)
    
                self.imageCache[unwrappedImage] = image
                dispatch_async(dispatch_get_main_queue(), {
                    cell.dealImage.image = image
    
                })
            }
            else {
    
            }
        })
        }
    
        else{
            cell.dealImage.image = image
        }
    
      return cell
    
    }
    

    Follow THIS tutorial for more Info. Hope this will help you.

    New Solution:

    Here is extension for it which is created by my friend Leo Dabus which is really simple to use:

    extension UIImageView {
        func downloadImageFrom(link link:String, contentMode: UIViewContentMode) {
            NSURLSession.sharedSession().dataTaskWithURL( NSURL(string:link)!, completionHandler: {
                (data, response, error) -> Void in
                dispatch_async(dispatch_get_main_queue()) {
                    self.contentMode =  contentMode
                    if let data = data { self.image = UIImage(data: data) }
                }
            }).resume()
        }
    }
    

    Now in your cellForRowAtIndexPath method assign image to cell this way:

    cell.cellImageView.image = UIImage(named: "placeholder")  //set placeholder image first.
    cell.cellImageView.downloadImageFrom(link: imageLinkArray[indexPath.row], contentMode: UIViewContentMode.ScaleAspectFit)  //set your image from link array.
    

    And as Rob suggested into comment here is some useful libraries which you can use:

    1. https://github.com/Alamofire/AlamofireImage
    2. https://github.com/onevcat/Kingfisher
    3. https://github.com/rs/SDWebImage
    4. https://github.com/kean/DFImageManager
    0 讨论(0)
  • 2020-11-29 00:39

    Details

    • Xcode 10.2.1 (10E1001), Swift 5

    Full sample

    Info.plist (add value)

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    

    Podfile

    target 'stackoverflow-28694645' do
      # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
      use_frameworks!
    
      # Pods for stackoverflow-28694645
      pod 'Alamofire'
      pod 'AlamofireImage'
    end
    

    Code

    import UIKit
    import Alamofire
    import AlamofireImage
    
    class ViewController: UIViewController {
    
        private weak var tableView: UITableView?
        private var items = [ItunceItem]()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let tableView = UITableView()
            view.addSubview(tableView)
            tableView.translatesAutoresizingMaskIntoConstraints = false
            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
            tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
            tableView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
            tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
            tableView.tableFooterView = UIView()
            tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
            tableView.rowHeight = 100
            tableView.separatorColor = .clear
            self.tableView = tableView
            loadData()
        }
    
        private func loadData() {
            let urlString = "https://itunes.apple.com/search?term=navigator"
            Alamofire.request(urlString).response { [weak self] response in
                guard let self = self, let data = response.data else { return }
                do {
                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase
                    self.items = try decoder.decode(ItunceItems.self, from: data).results
                    DispatchQueue.main.async { [weak self] in
                        guard let tableView = self?.tableView else { return }
                        tableView.delegate = self
                        tableView.dataSource = self
                        tableView.reloadData()
                    }
                } catch let error { print("\(error.localizedDescription)") }
            }
        }
    }
    
    extension ViewController: UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int { return 1 }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count }
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell
            return cell
        }
    }
    
    extension ViewController: UITableViewDelegate {
        func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            guard   let cell = cell as? TableViewCell,
                    let imageUrlString = items[indexPath.row].artworkUrl100,
                    let url = URL(string: imageUrlString) else { return }
            cell.photoImageView?.af_setImage(withURL: url)
        }
        func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            guard let cell = cell as? TableViewCell else { return }
            cell.photoImageView?.af_cancelImageRequest()
        }
    }
    
    struct ItunceItems: Codable { let results: [ItunceItem] }
    struct ItunceItem: Codable { var artworkUrl100: String? }
    
    class TableViewCell: UITableViewCell {
    
        private(set) weak var photoImageView: UIImageView?
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            selectionStyle = .none
            let imageView = UIImageView()
            addSubview(imageView)
            imageView.translatesAutoresizingMaskIntoConstraints = false
            imageView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 6).isActive = true
            imageView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor).isActive = true
            imageView.leftAnchor.constraint(equalTo: safeAreaLayoutGuide.leftAnchor).isActive = true
            imageView.rightAnchor.constraint(equalTo: safeAreaLayoutGuide.rightAnchor).isActive = true
            imageView.contentMode = .scaleAspectFit
            photoImageView = imageView
        }
    
        required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
        override func prepareForReuse() {
            super.prepareForReuse()
            photoImageView?.image = nil
        }
    }
    

    Result

    0 讨论(0)
提交回复
热议问题