Swift: asynchronously loading and displaying photos - ios

I'm struggling with the problem of displaying photo gallery from iPhone to collectionView.
Everything works fine if someone has 50 photos inside the gallery. The problem is when someone has thousands of photos, then the gallery is loading for 10 seconds, which is not good for my app. The same problem occurs when I'm loading images from Facebook. The app is waits until it downloads every photo then it displays. I'd like to display images one by one during the loading operation instead of waiting for it to load it all.
I know that I should use DispachQueue and I did but there is some bug that I don't see.
Here is the code I use to fetch images from iPhone gallery:
func grapPhotos() {
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResulat : PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) {
if fetchResulat.count > 0 {
for i in 0..<fetchResulat.count {
imgManager.requestImage(for: fetchResulat.object(at: i), targetSize: CGSize(width: 200, height:200), contentMode: PHImageContentMode.aspectFill, options: requestOptions, resultHandler: {
(image, eror) in
self.imageArray.append(image!)
DispatchQueue.main.async {
self.collectionView.reloadData()
}
})
}
} else {
print("You have no photos")
self.collectionView.reloadData()
}
}
}
And the code to display them in collectionView:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "galleryCell", for: indexPath) as! GalleryCollectionViewCell
let image = self.imageArray[indexPath.row]
DispatchQueue.main.async {
cell.gelleryImages.image = image
}
return cell
}
Probably the same problem is with my Facebook class so I will be very grateful for your help.

What you need is to add a fetchResult property to your collection view controller and fetch your image Assets inside viewDidLoad method.
var fetchResult: PHFetchResult<PHAsset> = PHFetchResult()
func fetchAssets() {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
}
override func viewDidLoad() {
super.viewDidLoad()
fetchAssets()
}
Next step is extend UIImageView to request the image data asynchronously setting its image on completion.
extension UIImageView {
func fetchImage(asset: PHAsset, contentMode: PHImageContentMode, targetSize: CGSize, version: PHImageRequestOptionsVersion = .current, deliveryMode: PHImageRequestOptionsDeliveryMode = .opportunistic) {
let options = PHImageRequestOptions()
options.version = version
options.deliveryMode = deliveryMode
PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: contentMode, options: options) { image, _ in
guard let image = image else { return }
switch contentMode {
case .aspectFill: self.contentMode = .scaleAspectFill
case .aspectFit: self.contentMode = .scaleAspectFit
#unknown default: fatalError()
}
self.image = image
}
}
}
Now you can fetch the images one at a time inside collection view cellForItemAt method:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
let asset = fetchResult.object(at: indexPath.row)
cell.imageView.fetchImage(asset: asset, contentMode: .aspectFill, targetSize: cell.imageView.frame.size * UIScreen.main.scale )
return cell
}
Don't forget to return the fetchResult count for numberOfItemsInSection method.
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return fetchResult.count
}
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
}
extension CGSize {
static func *(lhs: CGSize, rhs: CGFloat) -> CGSize {
.init(width: lhs.width * rhs, height: lhs.height * rhs)
}
}

Have you looked into SDWebImage? It has built in cache support so that the device doesn't have to download images it has previously downloaded every single time. It also has the benefit of being very simple to implement!

Related

How to display the photolibray as a UICollectionView or as an Asset Grid on Swift

What's the best way to produce something similar to a Twitter upload page where about 10 photo library pictures are displayed for the user to select one?
Below is the picture of what I'm trying to do.
Here is what I have done so far. However, it does not show when I run the app.
import photos
class UploadPostVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var imageArray = [UIImage]()
#IBOutlet weak var showPhotosCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
grabPhotos()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
print("wassup")
imageView.image = self.imageArray[indexPath.row]
return cell
}
func grabPhotos(){
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
if fetchResult.count > 0 {
for i in 0..<fetchResult.count{
//Used for fetch Image//
imgManager.requestImage(for: fetchResult.object(at: i) as PHAsset , targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: requestOptions, resultHandler: {
image, error in
let image = image! as UIImage
self.imageArray.append(image)
self.showPhotosCollectionView.reloadData()
print ("appended images")
})
self.showPhotosCollectionView.reloadData()
}
}
else {
print("you got no phots")
self.showPhotosCollectionView.reloadData()
}
}
You should set the collection view's delegate and dataSource. Just change your viewDidLoad function :
override func viewDidLoad() {
super.viewDidLoad()
self.showPhotosCollectionView.delegate = self
self.showPhotosCollectionView.dataSource = self
grabPhotos()
}

How To Paginate when using PHAsset to Fetch User Photo library

I am asking the same question as here
I do not understand how to implement to solution.
I have tried the following
fileprivate func fetchPhotos(indexSet: IndexSet) {
let allPhotos = PHAsset.fetchAssets(with: .image, options: assetsFetchOptions())
DispatchQueue.global(qos: .background).async {
allPhotos.enumerateObjects(at: indexSet, options: NSEnumerationOptions.concurrent, using: { (asset, count, stop) in
let imageManager = PHImageManager.default()
let targetSize = CGSize(width: 200, height: 200)
let options = PHImageRequestOptions()
options.isSynchronous = true
imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFit, options: options, resultHandler: { (image, info) in
if let image = image {
self.images.append(image)
self.assets.append(asset)
if self.selectedImage == nil {
self.selectedImage = image
}
}
DispatchQueue.main.async {
self.collectionView.reloadData()
self.hud.dismiss()
}
})
})
}
}
In cellForItemAt I tried doubling the indexes so the next 10 would load. The result i got was a never ending repetition of the first 10 posts.
Can someone please show the proper way to use this.
I tried to do what you want. I couldn't encapsulate it inside one function, coz it requires a few public variables, so here is the code for a UIViewController that has a UICollectionView which loads images by a page of 10 and when scrolled to the last cell it loads next 10 images and so on.
import UIKit
import Photos
import PhotosUI
class ImagesViewController: UIViewController ,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{
var assets = [PHAsset]()
var images = [UIImage]()
let page = 10
var beginIndex = 0
var endIndex = 9
var allPhotos : PHFetchResult<PHAsset>?
var loading = false
var hasNextPage = false
#IBOutlet weak var collectionView : UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let options = PHFetchOptions()
options.includeHiddenAssets = true
allPhotos = PHAsset.fetchAssets(with: .image, options: options)
getImages()
}
func getImages(){
endIndex = beginIndex + (page - 1)
if endIndex > allPhotos!.count {
endIndex = allPhotos!.count - 1
}
let arr = Array(beginIndex...endIndex)
let indexSet = IndexSet(arr)
fetchPhotos(indexSet: indexSet)
}
fileprivate func fetchPhotos(indexSet: IndexSet) {
if allPhotos!.count == self.images.count {
self.hasNextPage = false
self.loading = false
return
}
self.loading = true
DispatchQueue.global(qos: .background).async { [weak self] in
self?.allPhotos?.enumerateObjects(at: indexSet, options: NSEnumerationOptions.concurrent, using: { (asset, count, stop) in
guard let weakSelf = self else {
return
}
let imageManager = PHImageManager.default()
let targetSize = CGSize(width: weakSelf.view.frame.size.height - 20, height: 250)
let options = PHImageRequestOptions()
options.isSynchronous = true
imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFit, options: options, resultHandler: { (image, info) in
if let image = image {
weakSelf.images.append(image)
weakSelf.assets.append(asset)
}
})
if weakSelf.images.count - 1 == indexSet.last! {
print("last element")
weakSelf.loading = false
weakSelf.hasNextPage = weakSelf.images.count != weakSelf.allPhotos!.count
weakSelf.beginIndex = weakSelf.images.count
DispatchQueue.main.async {
weakSelf.collectionView.reloadData()
}
}
})
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let imgView = cell.viewWithTag(1) as! UIImageView
imgView.image = self.images[indexPath.row]
if self.hasNextPage && !loading && indexPath.row == self.images.count - 1 {
getImages()
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width:collectionView.frame.size.width - 20,height: 250)
}
}
Refinement and issues Resolved , Now below code Working fine
import Photos
import PhotosUI
class PhotoGalleryPaginationViewController: UIViewController,UICollectionViewDataSource,UICollectionViewDelegate {
var assets = [PHAsset]()
var images = [UIImage]()
let page = 10
var beginIndex = 0
var endIndex = 9
var allPhotos : PHFetchResult<PHAsset>?
var loading = false
var hasNextPage = false
#IBOutlet weak var collectionView : UICollectionView!
// MARK :- LIFE CYCLE
override func viewDidLoad() {
super.viewDidLoad()
// Cell Register
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
// Fetch Gallery
let options = PHFetchOptions()
options.includeHiddenAssets = true
allPhotos = PHAsset.fetchAssets(with: .image, options: options)
getImages()
// Do any additional setup after loading the view.
}
// MARK :- Methods
func getImages(){
endIndex = beginIndex + (page - 1)
if endIndex > allPhotos!.count {
endIndex = allPhotos!.count - 1
}
if endIndex > beginIndex {
let arr = Array(beginIndex...endIndex)
let indexSet = IndexSet(arr)
fetchPhotos(indexSet: indexSet)
}
}
fileprivate func fetchPhotos(indexSet: IndexSet) {
if allPhotos!.count == self.images.count {
self.hasNextPage = false
self.loading = false
return
}
self.loading = true
let targetSize = CGSize(width: 200, height: 200)
DispatchQueue.global(qos: .background).async { [weak self] in
self?.allPhotos?.enumerateObjects(at: indexSet, options: NSEnumerationOptions.concurrent, using: { (asset, count, stop) in
guard let weakSelf = self else {
return
}
let imageManager = PHImageManager.default()
let options = PHImageRequestOptions()
options.isSynchronous = true
imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFit, options: options, resultHandler: { (image, info) in
if let image = image {
weakSelf.images.append(image)
weakSelf.assets.append(asset)
}
})
if weakSelf.images.count - 1 == indexSet.last! {
print("last element")
weakSelf.loading = false
weakSelf.hasNextPage = weakSelf.images.count != weakSelf.allPhotos!.count
weakSelf.beginIndex = weakSelf.images.count
DispatchQueue.main.async {
weakSelf.collectionView.reloadData()
}
}
})
}
}
// MARK :- CollectionView DataSource and Delegate
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("image Count = \(images.count)")
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let imgView = UIImageView()
imgView.frame = CGRect(x: 0, y: 0, width: 150, height: 150)
imgView.image = self.images[indexPath.row]
cell.contentView.addSubview(imgView)
cell.clipsToBounds = true
// Fetch new Images
if self.hasNextPage && !loading && indexPath.row == self.images.count - 1 {
getImages()
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width:collectionView.frame.width/2,height: 150)
}
}

DidSelectItemAt Collection view issue

I'm having problem with didSelectItemAt in a UICollectionViewCell. I'm using a third party framework to select multiple photos from the library. The selected assets are then transferred and stored in a array of PHAssets. I use a small script for custom preview of the images when tapped on them. (It basically expands the image to full screen and put in and then you can swipe up or down to dismiss it). The problem is not with the images, they're properly displayed in my custom UICollectionViewCell. The problem is when I tap on them. For some reason it gives the wrong image and I'm not sure why.
var cameraPhotoUIImage: UIImage?
var assets = [PHAsset]()
lazy var assetsTurnedIntoImages =
{
return [UIImage]()
}()
lazy var imageManager = {
return PHCachingImageManager()
}()
extension PhotoVC : UICollectionViewDataSource, UICollectionViewDelegate
{
func setupCollectionView()
{
collectionView.dataSource = self
collectionView.delegate = self
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoPostCVCell", for: indexPath) as! PhotoPostCVCell
if let takenImage = cameraPhotoUIImage
{
cell.cellImage.image = takenImage
}
if assets.count > 0
{
let asset = assets[indexPath.row]
imageManager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFill, options: nil)
{ (image, info) in
cell.cellImage.contentMode = .scaleAspectFill
cell.cellImage.image = image!
self.assetsTurnedIntoImages.append(image!)
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
if assets.count > 0
{
return assets.count
}
else
{
return 1
}
}
// MARK: Preview Selected Image
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let postStoryboard = UIStoryboard(name: Storyboard_Post, bundle:nil)
if let destinationVC = postStoryboard.instantiateViewController(withIdentifier: "PreviewImageVC") as? PreviewImageVC
{
destinationVC.allowedDismissDirection = .both
destinationVC.maskType = .clear
if cameraPhotoUIImage != nil
{
destinationVC.transferedImageToPreview.image = cameraPhotoUIImage
destinationVC.showInteractive()
}
if assetsTurnedIntoImages.count > 0
{
print("Selected image to preview:",assetsTurnedIntoImages[indexPath.row] )
destinationVC.transferedImageToPreview.image = assetsTurnedIntoImages[indexPath.item]
destinationVC.showInteractive()
}
}
}
}
You should update the requestImage method. requestImage method looks like async. So that request does not wait block to complete. If you update your block like this, it should work.
imageManager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFill, options: nil)
{ (image, info) in
DispatchQueue.main.async {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoPostCVCell", for: indexPath) as! PhotoPostCVCell
cell.cellImage.contentMode = .scaleAspectFill
cell.cellImage.image = image!
self.assetsTurnedIntoImages.append(image!)
}
}

why collection view in empty when I fetch photos from gallery in swift 3?

I am Using swift 3 and want to see photo library IMAGES in the collection view But these codes doesn't work for me
before seeing my codes Attention to this :
**I will not receive any errors or crash I just can't see any of my image library in the collection view **
here is my codes :
import UIKit
import Photos
class collectionImageViewController: UIViewController , UICollectionViewDataSource , UICollectionViewDelegate {
var imageArray = [UIImage]()
#IBOutlet weak var collectionImageView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewImageCell", for: indexPath) as! CollectionViewImageCell
cell.theImage.image = imageArray[indexPath.row]
return cell
}
func getPhotosFromAlbum() {
let imageManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
if fetchResult.count > 0 {
for i in 0..<fetchResult.count {
imageManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 300, height: 300), contentMode: .aspectFill, options: requestOptions, resultHandler: { image, error in
self.imageArray.append(image!)
})
}
} else {
self.collectionImageView?.reloadData()
}
}
This is my whole code to load all images from gallery and load into collectioview. Please see this code
import UIKit
import Photos
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
let arr_img = NSMutableArray()
#IBOutlet var collview: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let allPhotosOptions : PHFetchOptions = PHFetchOptions.init()
allPhotosOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
let allPhotosResult = PHAsset.fetchAssets(with: .image, options: allPhotosOptions)
allPhotosResult.enumerateObjects({ (asset, idx, stop) in
self.arr_img.add(asset)
})
}
func getAssetThumbnail(asset: PHAsset, size: CGFloat) -> UIImage {
let retinaScale = UIScreen.main.scale
let retinaSquare = CGSize(width: size * retinaScale, height: size * retinaScale)//CGSizeMake(size * retinaScale, size * retinaScale)
let cropSizeLength = min(asset.pixelWidth, asset.pixelHeight)
let square = CGRect(x: 0, y: 0, width: cropSizeLength, height: cropSizeLength)//CGRectMake(0, 0, CGFloat(cropSizeLength), CGFloat(cropSizeLength))
let cropRect = square.applying(CGAffineTransform(scaleX: 1.0/CGFloat(asset.pixelWidth), y: 1.0/CGFloat(asset.pixelHeight)))
let manager = PHImageManager.default()
let options = PHImageRequestOptions()
var thumbnail = UIImage()
options.isSynchronous = true
options.deliveryMode = .highQualityFormat
options.resizeMode = .exact
options.normalizedCropRect = cropRect
manager.requestImage(for: asset, targetSize: retinaSquare, contentMode: .aspectFit, options: options, resultHandler: {(result, info)->Void in
thumbnail = result!
})
return thumbnail
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK:
//MARK: Collectioview methods
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return arr_img.count
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell",
for: indexPath)
let imgview : UIImageView = cell.viewWithTag(20) as! UIImageView
imgview.image = self.getAssetThumbnail(asset: self.arr_img.object(at: indexPath.row) as! PHAsset, size: 150)
return cell
}
}
You must reload the collectionView after your for loop like so
...
{
for i in 0..<fetchResult.count {
imageManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 300, height: 300), contentMode: .aspectFill, options: requestOptions, resultHandler: { image, error in
self.imageArray.append(image!)
})
self.collectionImageView?.reloadData()
}
...

Photos framework and reusable UICollectionViewCell

I have a UICollectionView to display photos from a device's album with the Photos framework. The photos are correctly displayed, but if I scroll fast (like when you tape at the top of the screen to go to the top of the collectionView), I have some photos which are not at the good indexPath. I just need to scroll a bit to put the bad photo out of the screen, and everything go back in place.
I clean the cell during prepareForReuse by canceling the current request.
I presume it's a problem with the asynchronous request of PHImageManager, but I don't know how to avoid this problem.
Here some code :
View Controller
extension AlbumDetailViewController : UICollectionViewDataSource {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photoList.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("PhotoCell", forIndexPath: indexPath) as! PhotoCollectionCell
cell.setImage(photoList.objectAtIndex(indexPath.row) as! PHAsset)
return cell
}
}
Custom CollectionViewCell
class PhotoCollectionCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
var requestId: PHImageRequestID!
let manager = PHImageManager.defaultManager()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func prepareForReuse() {
self.imageView.image = nil
manager.cancelImageRequest(self.requestId)
}
func setImage(asset: PHAsset) {
let option = PHImageRequestOptions()
option.resizeMode = .Fast
option.deliveryMode = .HighQualityFormat
self.requestId = manager.requestImageForAsset(asset, targetSize: CGSize(width: self.frame.size.width * UIScreen.mainScreen().scale, height: self.frame.size.height * UIScreen.mainScreen().scale), contentMode: PHImageContentMode.Default, options: option, resultHandler: {(result, info)->Void in
self.imageView.image = result
})
}
}
Thank you
Before calling requestImageForAsset method, set cell.tag equal indexPath.item, and after when getting image in callback, check indexPath.item and cell.tag, if this is matched do that
self.imageView.image = result. For example
cell.tag = indexPath.item
if let asset = assets?[indexPath.item] {
let option = PHImageRequestOptions()
option.isSynchronous = false
option.resizeMode = .exact
option.isNetworkAccessAllowed = true
DispatchQueue.global(qos: .userInitiated).async {
manager.requestImage(for: asset, targetSize: Constant.targetSize, contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
DispatchQueue.main.async {
if cell.tag == indexPath.item {
cell.imageView.image = result
}
}
})
}
}
Hope, it helps you

Resources