I have an album of images that is managed by a remote server. I would like to give the user an option to download the album and store it to a custom album in Photos. But since the album is dynamic (photos get added to it) the user can download it multiple times. I don't want to download the same pictures multiple times, only the new ones.
Is it possible to associate some metadata (unique id) when I store the image in the Photo app? And then check if that image already exists?
I am using the Photos Framework to create the custom album and save the photos.
Edit: Here is my code for creating the custom album and saving photos
/** Returns the first album from the photos app with the specified name. */
static func getAlbumWithName(name: String, completion: (album: PHAssetCollection?) -> Void) {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "localizedTitle = %@", name)
let fetchResult = PHAssetCollection.fetchAssetCollectionsWithType(PHAssetCollectionType.Album, subtype: PHAssetCollectionSubtype.Any, options: fetchOptions)
if fetchResult.count > 0 {
guard let album = fetchResult.firstObject as? PHAssetCollection else {return}
completion(album: album)
} else {
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(name)
}, completionHandler: { (result, error) in
if result {
FileUtils.getAlbumWithName(name, completion: completion)
} else {
completion(album: nil)
}
})
}
}
/** Adds an image to the specified photos app album */
private static func addImage(image: UIImage, toAlbum album: PHAssetCollection, completion: ((status: Bool) -> Void)?) {
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let assetPlaceholder = assetRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: album)
albumChangeRequest?.addAssets([assetPlaceholder!])
}) { (status, error) in
completion?(status: status)
}
}
All you need to do is read "localIdentifier" from the asset placeholder. I've augmented your code to return the identifier in the completion handler. You may like to deal with those optionals.
private static func addImage(image: UIImage, toAlbum album: PHAssetCollection, completion: ((status: Bool, identifier: String?) -> Void)?) {
var localIdentifier: String?
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let assetPlaceholder = assetRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: album)
albumChangeRequest?.addAssets([assetPlaceholder!])
localIdentifier = assetPlaceholder?.localIdentifier
}) { (status, error) in
completion?(status: status, identifier: localIdentifier)
}
}
When you want to read that asset again your load image method might look something like this (I haven't used your conventions or variable names). This will read the asset synchronously but I'm sure you can spot the async option.
internal func loadPhoto(identifier: String) -> UIImage? {
if assetCollection == nil {
return nil
}
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "localIdentifier = %@", identifier)
let fetchResult = PHAsset.fetchAssetsInAssetCollection(assetCollection, options: fetchOptions)
if fetchResult.count > 0 {
if let asset = fetchResult.firstObject as? PHAsset {
let options = PHImageRequestOptions()
options.deliveryMode = .HighQualityFormat
options.synchronous = true
var result: UIImage?
PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: CGSize(width: asset.pixelWidth, height: asset.pixelHeight), contentMode: .AspectFit, options: options, resultHandler: {(image: UIImage?, _: [NSObject: AnyObject]?) -> Void in
result = image
})
return result
}
}
return nil
}
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