图片未在 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
,否则不会有任何帖子循环。
此外,这里有几点需要考虑...
- 图像下载完成后您不会重新加载任何单元格 (downloadPhoto)
- 您没有缓存图片,所以您最终会经常下载图片。一旦你滚动你的 collectionView 并且单元格被重用,你将再次下载相同的图像。
- 您在这里没有有效地使用 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
}
在控制台中打印了空的 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
,否则不会有任何帖子循环。
此外,这里有几点需要考虑...
- 图像下载完成后您不会重新加载任何单元格 (downloadPhoto)
- 您没有缓存图片,所以您最终会经常下载图片。一旦你滚动你的 collectionView 并且单元格被重用,你将再次下载相同的图像。
- 您在这里没有有效地使用 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
}