图片未在 collectionView 中显示 Swift

Images not showing in collectionView Swift

在控制台中打印了空的 imagesArray,但我正在使用 downloadImages 函数下载它。在模拟器中,图像不会加载

import UIKit
import PinterestLayout
import ProgressHUD

class MainViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    @IBOutlet weak var collectionView: UICollectionView!

    var postsArray = [Post]()

    var imagesArray = [UIImage]()

    override func viewDidLoad() {
        super.viewDidLoad()

       if let layout = collectionView.collectionViewLayout as? PinterestLayout {
            layout.delegate = self
        }

        collectionView.contentInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

        loadItems()
        downloadPhoto()

    }

    func loadItems() {
        ref.child("Posts").observe(.childAdded) { (snapshot) in

            let snapshotValue = snapshot.value as! Dictionary<String,Any>

            if let title = snapshotValue["title"], let price = snapshotValue["price"], let downloadUrl = snapshotValue["downloadUrl"], let category = snapshotValue["category"], let senderUid = snapshotValue["senderUid"] {

                let post = Post()
                post.title = title as! String
                post.price = price as! String
                post.downloadUrl = downloadUrl as! String
                post.category = category as! String
                post.senderUid = senderUid as! String

                self.postsArray.append(post)

                self.collectionView.reloadData()

            }
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        tabBarController?.tabBar.shadowImage = UIImage()
        tabBarController?.tabBar.backgroundImage = UIImage()


    }

    func downloadPhoto(){
        DispatchQueue.global().async {
            self.imagesArray.removeAll() // this is the image array

            for i in 0..<self.postsArray.count {
                guard let url = URL(string: self.postsArray[i].downloadUrl) else {
                    continue
                }

                let group = DispatchGroup()

                print(url)
                print("-------GROUP ENTER-------")

                group.enter()
                URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
                    print(response?.suggestedFilename ?? url.lastPathComponent)

                    if let imgData = data, let image = UIImage(data: imgData) {
                        DispatchQueue.main.async() {
                            self.imagesArray.append(image)
                            self.collectionView.reloadData()
                        }
                    } else if let error = error {
                        print(error)
                    }

                    group.leave()
                }).resume()

                group.wait()
            }
        }
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return imagesArray.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mainCell", for: indexPath) as! MainCollectionViewCell

        cell.imgView.downloadImage(from: self.postsArray[indexPath.row].downloadUrl)

        return cell
    }



}

extension MainViewController: PinterestLayoutDelegate {

    func collectionView(_ collectionView: UICollectionView, heightForPhotoAtIndexPath indexPath: IndexPath) -> CGFloat {

        let image = imagesArray[indexPath.item]
        let height = image.size.height

        return height

    }
}

extension UIImageView {

    func downloadImage(from url: String){

        let urlRequest = URLRequest(url: URL(string: url)!)

        let task = URLSession.shared.dataTask(with: urlRequest) {
            (data,response,error) in

            if error != nil {
                print(error ?? error!)
                return
            }
            if let data = data {
                DispatchQueue.main.async {
                    self.image = UIImage(data: data)
                }
            }
        }
        task.resume()
    }

}

更新代码:

import UIKit
import PinterestLayout
import ProgressHUD
import Kingfisher

class MainViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    @IBOutlet weak var collectionView: UICollectionView!

    var postsArray = [Post]()

    var imagesArray = [UIImage]()

    override func viewDidLoad() {
        super.viewDidLoad()

       if let layout = collectionView.collectionViewLayout as? PinterestLayout {
            layout.delegate = self
        }

        collectionView.contentInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

        loadItems()


        collectionView.reloadData()
    }

    func loadItems() {
        ref.child("Posts").observe(.childAdded) { (snapshot) in

            let snapshotValue = snapshot.value as! Dictionary<String,Any>

            if let title = snapshotValue["title"], let price = snapshotValue["price"], let downloadUrl = snapshotValue["downloadUrl"], let category = snapshotValue["category"], let senderUid = snapshotValue["senderUid"] {

                let post = Post()
                post.title = title as! String
                post.price = price as! String
                post.downloadUrl = downloadUrl as! String
                post.category = category as! String
                post.senderUid = senderUid as! String

                self.postsArray.append(post)
                self.downloadPhoto()

                print(self.imagesArray.count)

                self.collectionView.reloadData()

            }
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        tabBarController?.tabBar.shadowImage = UIImage()
        tabBarController?.tabBar.backgroundImage = UIImage()

    }

    func downloadPhoto(){
        DispatchQueue.global().async {
            self.imagesArray.removeAll() // this is the image array

            for i in 0..<self.postsArray.count {
                guard let url = URL(string: self.postsArray[i].downloadUrl) else {
                    continue
                }

                let group = DispatchGroup()

                print(url)
                print("-------GROUP ENTER-------")

                group.enter()
                URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
                    print(response?.suggestedFilename ?? url.lastPathComponent)

                    if let imgData = data, let image = UIImage(data: imgData) {
                        DispatchQueue.main.async() {
                            self.imagesArray.append(image)
                            let post = Post()
                            post.image = image
                            self.collectionView.reloadData()
                        }
                    } else if let error = error {
                        print(error)
                    }
                    group.leave()
                }).resume()

                group.wait()
            }

        }
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return postsArray.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mainCell", for: indexPath) as! MainCollectionViewCell

        let resource = ImageResource(downloadURL: URL(string: postsArray[indexPath.row].downloadUrl)!, cacheKey: postsArray[indexPath.row].downloadUrl)
        cell.imgView.kf.setImage(with: resource)

        return cell
    }



}

extension MainViewController: PinterestLayoutDelegate {

    func collectionView(_ collectionView: UICollectionView, heightForPhotoAtIndexPath indexPath: IndexPath) -> CGFloat {

        let image = imagesArray[indexPath.row]
        let height = image.size.height / 6

        return height

    }
}
//AND POST CLASS

import UIKit

    class Post {
    var title : String = ""
    var category : String = ""
    var downloadUrl : String = ""
    var price : String = ""
    var senderUid : String = ""
    var image = UIImage()
}

您需要致电

downloadPhoto()

里面

loadItems()

因为两者都是异步的,这里

self.postsArray.append(post)
downloadPhoto()

注意:我建议在下载图像之前检查缓存或更好地使用SDWebImage

正如Sh_Khan所说,你需要在loadItems完成后调用downloadPhoto,否则不会有任何帖子循环。

此外,这里有几点需要考虑...

  1. 图像下载完成后您不会重新加载任何单元格 (downloadPhoto)
  2. 您没有缓存图片,所以您最终会经常下载图片。一旦你滚动你的 collectionView 并且单元格被重用,你将再次下载相同的图像。
  3. 您在这里没有有效地使用 DispatchGroup(无论如何在 downloadPhoto 中),您似乎一次(或尝试)下载一张图像,没有利用并行下载。如果您打算这样做,请使用串行队列。但这会大大减慢加载图像的速度。

我更喜欢使用 KingFisher 来下载和缓存图像,该库已经为您管理了大部分,让您专注于您的应用程序。

如果您不想使用图书馆,这样的事情应该会有所帮助...

var imageCache = [String: UIImage]()

func downloadImage(from url: String){

    if let image = imageCache[url] as? UIImage {
        self.image = image
        return
    }

    let urlRequest = URLRequest(url: URL(string: url)!)

    let task = URLSession.shared.dataTask(with: urlRequest) {
        (data,response,error) in

        if error != nil {
            print(error ?? error!)
            return
        }

        if let data = data {
            DispatchQueue.main.async {
                let image = UIImage(data: data)
                imageCache[url] = image
                self.image = image
            }
        }
    }

    task.resume()
}

翠鸟示例:

imageView.kf.setImage(with: url, completionHandler: { 
    (image, error, cacheType, imageUrl) in
    // image: Image? `nil` means failed
    // error: NSError? non-`nil` means failed
    // cacheType: CacheType
    //                  .none - Just downloaded
    //                  .memory - Got from memory cache
    //                  .disk - Got from disk cache
    // imageUrl: URL of the image
})

所以有一个 postsArray 和 images 数组

var postsArray = [Post]()

var images = [String: UIImage]() // dictionary, maps url to image

然后当您收到 Post:

let post = Post()
post.title = title as! String
post.price = price as! String
post.downloadUrl = downloadUrl as! String
post.category = category as! String
post.senderUid = senderUid as! String

self.postsArray.append(post)
imageView.kf.setImage(with: url, completionHandler: { (image, error, cacheType, imageUrl) in
    // check image is not nil etc
    images[url] = image
    collectionView.reloadData()
}

CellForRowAt:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mainCell", for: indexPath) as! MainCollectionViewCell

    cell.imgView.image = images[postsArray[indexPath.row].downloadUrl]
    return cell
}