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