I am using below code for getting videos(URL, Durations, Thumbnails). After Fetching data i am displaying it on CollectionView
.
The main problem is that, some video and its thumbnails not match each other. Can any one please tell me how i can fix it, or any other better solution?
Thanks
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.imgV.image = photoLibrary[indexPath.row]
let duration: TimeInterval = videosDuration[indexPath.row] // 2 minutes, 30 seconds
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.allowedUnits = [ .minute, .second ]
formatter.zeroFormattingBehavior = [ .pad ]
let formattedDuration = formatter.string(from: duration)
cell.duration.text = "\(String(describing: formattedDuration!))"
return cell
}
func grabPhotos(){
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = false
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .video, 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 imageOfVideo = image! as UIImage
self.photoLibrary.append(imageOfVideo)
})
//Used for fetch Video//
imgManager.requestAVAsset(forVideo: fetchResult.object(at: i) as PHAsset, options: PHVideoRequestOptions(), resultHandler: {(avAsset, audioMix, info) -> Void in
if let asset = avAsset as? AVURLAsset {
self.videoURL.append(asset.url)
let duration : CMTime = asset.duration
let durationInSecond = CMTimeGetSeconds(duration)
self.videosDuration.append(durationInSecond)
}
})
}
}
else{
//showAllertToImportImage()//A function to show alert
}
}
}
Since photos are being fetched asynchronously so the order is not maintained in the images and videos array, so to get the corresponding image for the video you can use dictionaries to store the result
I have made some modifications in your code, please check
var imageDictionary = [String: AnyObject]()
var videoDictionary = [String: AnyObject]()
func fetchData(){
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = false
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .video, 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 imageOfVideo = image! as UIImage
//self.photoLibrary.append(imageOfVideo)
let key = "\(i)"
self.imageDictionary[key] = imageOfVideo
})
//Used for fetch Video//
imgManager.requestAVAsset(forVideo: fetchResult.object(at: i) as PHAsset, options: PHVideoRequestOptions(), resultHandler: {(avAsset, audioMix, info) -> Void in
if let asset = avAsset as? AVURLAsset {
//let videoData = NSData(contentsOf: asset.url)
self.videoURL.append(asset.url)
//print(asset.url)
let duration : CMTime = asset.duration
let durationInSecond = CMTimeGetSeconds(duration)
//self.videosDuration.append(durationInSecond)
//print(durationInSecond)
let key = "\(i)"
self.videoDictionary[key] = ["VideoURL" : asset.url, "VideoDuration" : durationInSecond]
}
})
}
}
else{
//showAllertToImportImage()//A function to show alert
}
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.imageDictionary.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//You can access the values like this....
let key = "\(indexPath.row)"
cell.image = self.imageDictionary[key] as? UIImage
let singleVideo = self.videoDictionary[key] as? [String: AnyObject]
cell.videoURL = singleVideo["VideoURL"] as? URL
cell.videoDuration = singleVideo["VideoDuration"] as? CMTime
}