9

I want to retrieve all the photos from all the local albums on the device. Basically all the photos that are on the device Will the list of local identifiers be unique ? What is the best approach for this using the photos framework.

My question is not duplicate since the other question talks about also cloud assets and assets that are not on the device. When retrieving actual data of the image it returns null data when trying to fetch synchronize.

Noam Segev
  • 395
  • 3
  • 20
  • Possible duplicate of [iOS 8 Photos framework: Get a list of all albums with iOS8](http://stackoverflow.com/questions/25981374/ios-8-photos-framework-get-a-list-of-all-albums-with-ios8) –  Mar 30 '17 at 10:03
  • "the local albums on the device. Basically all the photos that are on the device" Can't an album can be local but contain a photo that is in the cloud? – matt Apr 16 '17 at 22:05

3 Answers3

3

I want to retrieve all the photos from all the local albums on the device. Basically all the photos that are on the device

Edit: fetchOptions.includeAssetSourceTypes = .typeUserLibrary see below code

That's how I do it:

var fetchResult: PHFetchResult<PHAsset>!

...

let fetchOptions = PHFetchOptions()     
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.includeAssetSourceTypes = .typeUserLibrary

fetchResult = PHAsset.fetchAssets(with: fetchOptions)

Then if I want to use it as UImage or thumbnail (also if you want the image as Data use this let imageData: NSData = UIImagePNGRepresentation(myImage)) I use:

/* 
 * From an asset to a UIImage, also can be used for thumbnail (if you change the :targetSize:)
 */
func getAsset(_ asset: PHAsset) -> UIImage {

    //var thumbnail = UIImage()
    var imageData = Data()

    let options = PHImageRequestOptions()
    options.isSynchronous = true
    options.deliveryMode = .opportunistic
    options.resizeMode = .fast
    options.isNetworkAccessAllowed = false

    PHImageManager.default().requestImage(for: asset, targetSize: view.frame.size, contentMode: .aspectFill, options: options) { image, info in

      //thumbnail = image!
        imageData: NSData = UIImagePNGRepresentation(image)
    }
    //You can check if the UIImage is nil. If it is nil is an iCloud image
    //return thumbnail
    return imageData
}

You will probably customize the above code or add more features based on your needs!

The above code is written and tested using Swift 3.1 and Xcode 8.3.1

According to Apple's Docs

isNetworkAccessAllowed A Boolean value that specifies whether Photos can download the requested image from iCloud. If true, and the requested image is not stored on the local device, Photos downloads the image from iCloud. To be notified of the download’s progress, use the progressHandler property to provide a block that Photos calls periodically while downloading the image. If false (the default), and the image is not on the local device, the PHImageResultIsInCloudKey value in the result handler’s info dictionary indicates that the image is not available unless you enable network access.

Use the getAsset() method for retrieving the image from the asset. It works

George Vardikos
  • 2,345
  • 1
  • 14
  • 25
  • 1
    This returns also cloud photos and i tuens sync photos. So again I want all the photos that are physically on the device – Noam Segev Apr 18 '17 at 11:27
  • but i want to know if the image data is on the device before trying to retrieve it is that possible ? – Noam Segev Apr 18 '17 at 15:36
  • Reading the documentation I do not think that there is a straightforward way . Thus, you can combine the fetchResult with the getAsset method to have your solution. Fetching photos with this way is fast enough in terms of computational speed. Also have you checked the metadata of images in case they contain some specific values if they are in iCloud? If this is, you can filter on them and fetch only them. – George Vardikos Apr 18 '17 at 22:32
  • I am checking if the data is nil, I want a way without the image data fetch. How Can i make sure the data will not be nil before the fetch. – Noam Segev Apr 23 '17 at 05:58
2
PHFetchResult *smartAlbums;
smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];

    for (NSInteger i =0; i < smartAlbums.count; i++)
{
    @autoreleasepool
    {
        PHAssetCollection *assetCollection = smartAlbums[i];
        //Camera Roll
        //All Photos //Moments
        NSLog(@"assetCollection.localizedTitle---%@",assetCollection.localizedTitle);

        // here you will get camera roll photos

        if([assetCollection.localizedTitle isEqualToString:@"Camera Roll"] || [assetCollection.localizedTitle isEqualToString:@"All Photos"] )
        {
            PHFetchOptions *options1 = [[PHFetchOptions alloc] init];
            options1.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
            options1.predicate = [NSPredicate predicateWithFormat:@"mediaType = %d",PHAssetMediaTypeImage];

            // here you will get all assets of your camera roll images in assetsFetchResult
            PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:options1];
        }
    }
}
Shaik Thuphel
  • 75
  • 2
  • 10
1

Step 1.

Embed Photos.framework in your project

Step 2

#import <Photos/Photos.h>

Step 3

Add NSPhotoLibraryUsageDescription key on plist

<key>NSPhotoLibraryUsageDescription</key>
<string>${PRODUCT_NAME} PhotoLibrary Usage</string>

Step 4

Write this code to get PHFetchResult

PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];

PHFetchResult *tempAssetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
tempAssetsFetchResults = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
Jagveer Singh
  • 2,258
  • 19
  • 34