What I'm trying to accomplish: For this project, I will mention only two source files: (1) RPPhotoLibrary.swift - A UICollectionViewController and (2) PhotoThumbnail.swift: - A UICollectionViewCell. I want to load the images (and videos) from the user's photo library (preferably all of them) and present them into a UICollectionViewCell for each cell in the UICollectionViewController. For some reason, I am able to load photos but am not able to load all the photos. This is my code for the first source file: RPPhotoLibrary.swift:
import UIKit
import Photos
private let reuseIdentifier = "PhotoCell"
class RPPhotoLibrary: UICollectionViewController, UIImagePickerControllerDelegate {
// By default make locating album false
var assetCollection: PHAssetCollection!
var photosAsset: PHFetchResult!
var assetThumbnailSize: CGSize!
@IBAction func cancelButton(sender: AnyObject) {
self.dismissViewControllerAnimated(false, completion: nil)
}
// =================== THIS BUTTON TAKES A PHOTO =====================================================
@IBAction func captureMoment(sender: AnyObject) {
let imagePicker = UIImagePickerController()
if (UIImagePickerController.isSourceTypeAvailable(.Camera)) {
if UIImagePickerController.availableCaptureModesForCameraDevice(.Rear) != nil {
imagePicker.allowsEditing = true
imagePicker.sourceType = .Camera
imagePicker.cameraCaptureMode = .Photo
presentViewController(imagePicker, animated: false, completion: {} )
} else {
// postAlert("Rear camera does not exist", message: "RedPlanet cannot access the camera")
var alert = UIAlertView(title: "Your phone doesn't have a rear camera!",
message: "RedPlanet cannot access the camera.",
delegate: self,
cancelButtonTitle: "ok")
alert.show()
}
} else {
// postAlert("Camera not accessible", message: "RedPlanet cannot access the camera")
var alert = UIAlertView(title: "Cannot access camera.",
message: "RedPlanet cannot access the camera.",
delegate: self,
cancelButtonTitle: "ok")
alert.show()
}
}
@IBOutlet weak var thumbNail: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let fetchOptions = PHFetchOptions()
let collection:PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Moment, subtype: .Any, options: fetchOptions)
if let first_Obj:AnyObject = collection.firstObject{
//found the album
self.assetCollection = first_Obj as! PHAssetCollection
}
}
override func viewWillAppear(animated: Bool) {
// Get size of the collectionView cell for thumbnail image
if let layout = self.collectionView!.collectionViewLayout as? UICollectionViewFlowLayout{
let cellSize = layout.itemSize
self.assetThumbnailSize = CGSizeMake(cellSize.width, cellSize.height)
}
//fetch the photos from collection
self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.assetCollection, options: nil)
self.collectionView!.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "selectedPhoto(s)"){
if let controller: SelectedPhoto = segue.destinationViewController as? SelectedPhoto{
if let cell = sender as? PhotoThumbnail {
if let indexPath: NSIndexPath = self.collectionView!.indexPathForCell(cell){
controller.index = indexPath.item
controller.photosAsset = self.photosAsset
controller.assetCollection = self.assetCollection
}
}
}
}
}
// MARK: UICollectionViewDataSource
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
var count: Int = 0
if(self.photosAsset != nil){
count = self.photosAsset.count
}
return count;
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: PhotoThumbnail = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! PhotoThumbnail
//Modify the cell
let asset: PHAsset = self.photosAsset[indexPath.item] as! PHAsset
PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: self.assetThumbnailSize, contentMode: .AspectFill, options: nil, resultHandler: {(result, info)in
if let image = result {
cell.setThumbnailImage(image)
}
})
return cell
}
// MARK: - UICollectionViewDelegateFlowLayout methods
func collectionView(collectinView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
return 4
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return 1
}
// UIImagePickerControllerDelegate Methods
func imagePickerControllerDidCancel(picker: UIImagePickerController){
picker.dismissViewControllerAnimated(true, completion: nil)
}
// MARK: UICollectionViewDelegate
/*
// Uncomment this method to specify if the specified item should be selected
override func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
*/
// Uncomment these methods to specify if an action menu should be displayed for the specified item, and react to actions performed on the item
override func collectionView(collectionView: UICollectionView, shouldShowMenuForItemAtIndexPath indexPath: NSIndexPath) -> Bool {
return false
}
override func collectionView(collectionView: UICollectionView, canPerformAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) -> Bool {
return false
}
override func collectionView(collectionView: UICollectionView, performAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) {
self.dismissViewControllerAnimated(false, completion: nil)
}
}
Here's my code for the second source file (2): PhotoThumbnail.swift:
import UIKit
class PhotoThumbnail: UICollectionViewCell {
@IBOutlet weak var thumbNail: UIImageView!
func setThumbnailImage(thumbNailImage: UIImage) {
self.thumbNail.image = thumbNailImage
}
}
The Problem: For some reason, I am unable to load all the images from the Photos Library with 8 columns and I want to load 4 columns of each photo from the photo library. If anyone could help me out or even give me tutorials for something likes this, that would be greatly appreciated!
I updated it for Swift 3, this is pulling in all photos:
import UIKit
import Photos
class TestViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UIImagePickerControllerDelegate {
@IBOutlet weak var cameraRollCollectionView: UICollectionView!
var assetCollection: PHAssetCollection!
var photosAsset: PHFetchResult<AnyObject>!
var assetThumbnailSize: CGSize!
override func viewDidLoad() {
super.viewDidLoad()
let fetchOptions = PHFetchOptions()
let collection:PHFetchResult = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let first_Obj:AnyObject = collection.firstObject{
//found the album
self.assetCollection = first_Obj as! PHAssetCollection
}
}
override func viewWillAppear(_ animated: Bool) {
// Get size of the collectionView cell for thumbnail image
if let layout = self.cameraRollCollectionView!.collectionViewLayout as? UICollectionViewFlowLayout{
let cellSize = layout.itemSize
self.assetThumbnailSize = CGSize(width: cellSize.width, height: cellSize.height)
}
//fetch the photos from collection
self.photosAsset = (PHAsset.fetchAssets(in: self.assetCollection, options: nil) as AnyObject!) as! PHFetchResult<AnyObject>!
self.cameraRollCollectionView!.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
var count: Int = 0
if(self.photosAsset != nil){
count = self.photosAsset.count
}
return count;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cameraCell", for: indexPath as IndexPath) as! UserImagesCollectionViewCell
//Modify the cell
let asset: PHAsset = self.photosAsset[indexPath.item] as! PHAsset
PHImageManager.default().requestImage(for: asset, targetSize: self.assetThumbnailSize, contentMode: .aspectFill, options: nil, resultHandler: {(result, info)in
if result != nil {
cell.userImage.image = result
}
})
return cell
}
// MARK: - UICollectionViewDelegateFlowLayout methods
func collectionView(collectinView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
return 4
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return 1
}
// UIImagePickerControllerDelegate Methods
func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
picker.dismiss(animated: true, completion: nil)
}
}
I assume the reason of your problem is these lines of your code:
let collection:PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Moment, subtype: .Any, options: fetchOptions)
if let first_Obj:AnyObject = collection.firstObject{
//found the album
self.assetCollection = first_Obj as! PHAssetCollection
}
The first object of fetch result is not an album, it's a moment (a photo group). Check the documentation:
PHAssetCollectionTypeMoment. A moment in the Photos app. The Photos app automatically creates moments to group assets by time and location.
If you want to show photos in a first album, you just need to replace .Moment with .Album. If you want to show all the photos, you need to process all objects in PHFetchResult, not just first of them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With