19

I've tried to fetch photos from the library. It works, but I just got 3 photos from 9 photos from the library. Here's my code:

let options = PHFetchOptions()
    let userAlbums = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.album, subtype: PHAssetCollectionSubtype.any, options: options)

    let userPhotos = PHAsset.fetchKeyAssets(in: userAlbums.firstObject!, options: nil)
    let imageManager = PHCachingImageManager()

    userPhotos?.enumerateObjects({ (object: AnyObject!, count: Int, stop: UnsafeMutablePointer) in
        if object is PHAsset {
            let obj:PHAsset = object as! PHAsset

            let fetchOptions = PHFetchOptions()
            fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
            fetchOptions.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue)

            let options = PHImageRequestOptions()
            options.deliveryMode = .fastFormat
            options.isSynchronous = true

            imageManager.requestImage(for: obj, targetSize: CGSize(width: obj.pixelWidth, height: obj.pixelHeight), contentMode: .aspectFill, options: options, resultHandler: { img, info in

                self.images.append(img!)
            })
        }
    })

When I tried images.count, it said 3. Can anyone help me to find my mistake and get all photos? Big thanks!

catcatcat
  • 377
  • 1
  • 5
  • 19

3 Answers3

34

Try this,

first import photos

import Photos

then declare Array for store photo before viewDidLoad()

var allPhotos : PHFetchResult<PHAsset>? = nil

Now write code for fetch photo in viewDidLoad()

    /// Load Photos
    PHPhotoLibrary.requestAuthorization { (status) in
        switch status {
        case .authorized:
            print("Good to proceed")
            let fetchOptions = PHFetchOptions()
            self.allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)
        case .denied, .restricted:
            print("Not allowed")
        case .notDetermined:
            print("Not determined yet")
        }
    }

Now write this code for display image from Array

/// Display Photo
let asset = allPhotos?.object(at: indexPath.row)
self.imageview.fetchImage(asset: asset!, contentMode: .aspectFit, targetSize: self.imageview.frame.size) 


// Or Display image in Collection View cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", for: indexPath) as! SelectPhotoCell

    let asset = allPhotos?.object(at: indexPath.row)
    cell.imgPicture.fetchImage(asset: asset!, contentMode: .aspectFit, targetSize: cell.imgPicture.frame.size)

    return cell
}

extension UIImageView{
 func fetchImage(asset: PHAsset, contentMode: PHImageContentMode, targetSize: CGSize) {
    let options = PHImageRequestOptions()
    options.version = .original
    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
        }
        self.image = image
    }
   }
}
Sapana Ranipa
  • 889
  • 7
  • 20
9

Swift 5 - Update

First import Photos

Import Photos

Create a variable to hold all the images

var images = [UIImage]()

Main function to grab the assets and request image from asset

fileprivate func getPhotos() {

    let manager = PHImageManager.default()
    let requestOptions = PHImageRequestOptions()
    requestOptions.isSynchronous = false
    requestOptions.deliveryMode = .highQualityFormat
    // .highQualityFormat will return better quality photos
    let fetchOptions = PHFetchOptions()
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

    let results: PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
    if results.count > 0 {
        for i in 0..<results.count {
            let asset = results.object(at: i)
            let size = CGSize(width: 700, height: 700)
            manager.requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: requestOptions) { (image, _) in
                if let image = image {
                    self.images.append(image)
                    self.collectionView.reloadData()
                } else {
                    print("error asset to image")
                }
            }
        }
    } else {
        print("no photos to display")
    }

}
Toto
  • 593
  • 7
  • 20
  • 2
    adding explanation to your answer will be helpful – RamPrakash Jan 22 '20 at 11:38
  • 2
    Works perfectly, but after fetching 3400 image from my library, app crashes because of this error: "Message from debugger: Terminated due to memory issue" . How can I handle memory warning? – Ömer Karaca Apr 17 '21 at 12:05
1

Check first in info.plist that your app is authorized to access photos from library. than Use the below code to access all photos:

PHPhotoLibrary.requestAuthorization { (status) in
        switch status {
        case .authorized:
            print("You Are Authrized To Access")
            let fetchOptions = PHFetchOptions()
            let allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)
            print("Found number of:  \(allPhotos.count) images")
        case .denied, .restricted:
            print("Not allowed")
        case .notDetermined:
            print("Not determined yet")
        }
    }
MRizwan33
  • 2,723
  • 6
  • 31
  • 42
  • @cathrinnatalia Your question is about how to fetch the photos from library. Please don't expand your question. – TheTiger Mar 21 '18 at 05:12
  • extend the scope of allPhotos variable by taking it on top and within in the class than count from it and use it in collectionview. but this method should be in viewDidLoad. – MRizwan33 Mar 21 '18 at 06:56