web-dev-qa-db-ja.com

Swift非同期読み込みイメージ

私はURL非同期からの画像表示に取り組んでいます。ダウンロードイメージ用の新しいスレッドを作成し、main threadで更新しようとしました。

func asyncLoadImg(product:Product,imageView:UIImageView){
    let downloadQueue = dispatch_queue_create("com.myApp.processdownload", nil)
    dispatch_async(downloadQueue){
        let data = NSData(contentsOfURL: NSURL(string: product.productImage)!)
        var image:UIImage?
        if data != nil{
            image = UIImage(data: data!)
        }
        dispatch_async(dispatch_get_main_queue()){
            imageView.image = image
        }

    }
}

私がそれをデバッグしようとしたとき、dispatch_async(downloadQueue)に関しては、funcを飛び出しました。なにか提案を?どうも

29
Janice Zhan

Swift 3.0+更新コード:(jamesrochabrunリンクから助けを借りました https://github.com/jamesrochabrun/JSONTutorialFinal =)

let imageCache = NSCache<NSString, UIImage>()

extension UIImageView {

    func imageFromServerURL(_ URLString: String, placeHolder: UIImage?) {

        self.image = nil
        if let cachedImage = imageCache.object(forKey: NSString(string: URLString)) {
            self.image = cachedImage
            return
        }

        if let url = URL(string: URLString) {
            URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in

                //print("RESPONSE FROM API: \(response)")
                if error != nil {
                    print("ERROR LOADING IMAGES FROM URL: \(error)")
                    DispatchQueue.main.async {
                        self.image = placeHolder
                    }
                    return
                }
                DispatchQueue.main.async {
                    if let data = data {
                        if let downloadedImage = UIImage(data: data) {
                            imageCache.setObject(downloadedImage, forKey: NSString(string: URLString))
                            self.image = downloadedImage
                        }
                    }
                }
            }).resume()
        }
    }
}

Swift 3更新コード:

extension UIImageView {
    public func imageFromServerURL(urlString: String) {
        self.image = nil
        URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in

            if error != nil {
                print(error)
                return
            }
            DispatchQueue.main.async(execute: { () -> Void in
                let image = UIImage(data: data!)
                self.image = image
            })

        }).resume()
    }}

Swift 2.2コード:

 extension UIImageView {
        public func imageFromServerURL(urlString: String) {
    self.image = nil
            NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: { (data, response, error) -> Void in

                if error != nil {
                    print(error)
                    return
                }
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    let image = UIImage(data: data!)
                    self.image = image
                })

            }).resume()
        }}

サーバーurlから画像を読み込むためにこれを行う必要があるところはどこでも:

  1. Swift 3.0を使用+プレースホルダーイメージを使用して更新されたコード:UIImageView.imageFromServerURL(URLString: "here server url"、placeHolder:uiimage形式のプレースホルダーイメージ)

  2. Swfit 3以下:UIImageView.imageFromServerURL( "here server url")

シンプル!

90

Swift3extensionを使用します。 ネットワークの問題を解決するには、NSCacheを使用することをお勧めします。

import UIKit

let imageCache = NSCache<NSString, AnyObject>()

extension UIImageView {
    func loadImageUsingCache(withUrl urlString : String) {
        let url = URL(string: urlString)
        self.image = nil

        // check cached image
        if let cachedImage = imageCache.object(forKey: urlString as NSString) as? UIImage {
            self.image = cachedImage
            return
        }

        // if not, download image from url
        URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
            if error != nil {
                print(error!)
                return
            }

            DispatchQueue.main.async {
                if let image = UIImage(data: data!) {
                    imageCache.setObject(image, forKey: urlString as NSString)
                    self.image = image
                }
            }

        }).resume()
    }
}

それが役立つことを願っています!

25
javimuu

Shobhakar Tiwariの答えを引き継いで、これらのケースでエラーの場合にデフォルトのイメージを持っていると、ロードの目的で役立つことが多いと思うので、オプションのデフォルトのイメージを含めるように更新しました。

スイフト3

extension UIImageView {
public func imageFromServerURL(urlString: String, defaultImage : String?) {
    if let di = defaultImage {
        self.image = UIImage(named: di)
    }

    URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in

        if error != nil {
            print(error ?? "error")
            return
        }
        DispatchQueue.main.async(execute: { () -> Void in
            let image = UIImage(data: data!)
            self.image = image
        })

    }).resume()
  }
}
3
spogebob92

このソリューションは、不必要な画像更新なしでスクロールを非常に高速にします。セルクラスにurlプロパティを追加する必要があります。

class OfferItemCell: UITableViewCell {
    @IBOutlet weak var itemImageView: UIImageView!
    @IBOutlet weak var titleLabel: UILabel! 
    var imageUrl: String?
}

そして拡張子を追加します:

import Foundation
import UIKit

let imageCache = NSCache<AnyObject, AnyObject>()
let imageDownloadUtil: ImageDownloadUtil = ImageDownloadUtil()

extension OfferItemCell {
    func loadImageUsingCacheWithUrl(urlString: String  ) {
         self.itemImageView.image = nil
        if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
            self.itemImageView.image = cachedImage
            return
        }
        DispatchQueue.global(qos: .background).async {
            imageDownloadUtil.getImage(url: urlString, completion: {
                image in
                DispatchQueue.main.async {
                    if self.imageUrl == urlString{
                        imageCache.setObject(image, forKey: urlString as AnyObject)
                     self.itemImageView.image = image
                    }
                }
            })
        }
    }
}

また、それを改善し、より一般的なセルクラス(CustomCellWithImageなど)にコードを抽出して再利用可能にすることもできます。

1

blinkまたはin Swift 4効果なしで非同期画像を読み込む最も一般的なchanging imagesの方法は、次のようなカスタムUIImageViewクラスに使用します。

//MARK: - 'asyncImagesCashArray' is a global varible cashed UIImage
var asyncImagesCashArray = NSCache<NSString, UIImage>()

class AyncImageView: UIImageView {

//MARK: - Variables
private var currentURL: NSString?

//MARK: - Public Methods

func loadAsyncFrom(url: String, placeholder: UIImage?) {
    let imageURL = url as NSString
    if let cashedImage = asyncImagesCashArray.object(forKey: imageURL) {
        image = cashedImage
        return
    }
    image = placeholder
    currentURL = imageURL
    guard let requestURL = URL(string: url) else { image = placeholder; return }
    URLSession.shared.dataTask(with: requestURL) { (data, response, error) in
        DispatchQueue.main.async { [weak self] in
            if error == nil {
                if let imageData = data {
                    if self?.currentURL == imageURL {
                        if let imageToPresent = UIImage(data: imageData) {
                            asyncImagesCashArray.setObject(imageToPresent, forKey: imageURL)
                            self?.image = imageToPresent
                        } else {
                            self?.image = placeholder
                        }
                    }
                } else {
                    self?.image = placeholder
                }
            } else {
                self?.image = placeholder
            }
        }
    }.resume()
}
}

UITableViewCell以下でこのクラスを使用する例:

class CatCell: UITableViewCell {

//MARK: - Outlets
@IBOutlet weak var catImageView: AyncImageView!

//MARK: - Variables

var urlString: String? {
    didSet {
        if let url = urlString {
            catImageView.loadAsyncFrom(url: url, placeholder: nil)
        }
    }
}

override func awakeFromNib() {
    super.awakeFromNib()
}
}
1
PiterPan

最良の方法の1つは、 SDWebImage を使用することです。

迅速な例:

import SDWebImage
imageView.sd_setImage(with: URL(string: "ImageUrl"), placeholderImage: UIImage(named: "placeholder.png"))

目標Cの例:

#import <SDWebImage/UIImageView+WebCache.h>
[imageView sd_setImageWithURL:[NSURL URLWithString:@"ImageUrl"]
         placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
1
Rajesh

ここで、このコードが役に立つかもしれません。

   let cacheKey = indexPath.row
   if(self.imageCache?.objectForKey(cacheKey) != nil){
           cell.img.image = self.imageCache?.objectForKey(cacheKey) as? UIImage
    }else{
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
             if let url = NSURL(string: imgUrl) {
                  if let data = NSData(contentsOfURL: url) {
                            let image: UIImage = UIImage(data: data)!
                            self.imageCache?.setObject(image, forKey: cacheKey)
                            dispatch_async(dispatch_get_main_queue(), {
                                cell.img.image = image
                            })
                        }
                    }
                })
            }

この画像では、テーブルビューのスクロールを遅らせることなくダウンロードしてキャッシュします

1