Reputation: 881
I am using Xcode 6.3
with swift (I think version 1.2). My app downloads photos from a custom server on the web. Then I want it to save the photo with a given file name to the custom photo album, which was has created via the Photos Framework. I need to be able to control the photo/filename because I keep track of which photos I have downloaded in a database and later need to view them by name.
I created a custom PhotoAlbum class that I am trying to wrap all of the logic for interacting with the photo albums in. Once I download a photo I can call the following code and it works as far as creating the album and saving the photo, but as you will notice in the savePhoto()
method I don't know where/how to use the photoName variable to name the photo when saving. Eventually, I will also need to know how to retrieve the photo by name as well in the loadPhoto()
method.
Thanks for any help/advice you can give me.
let myAlbum = PhotoAlbum("MyAlbum")
myAlbum.savePhoto(downloadedPhoto, 12)
class PhotoAlbum {
var albumName: String = ""
var albumExists: Bool = false
var assetCollection: PHAssetCollection!
var photosAsset: PHFetchResult!
init(albumName: String) {
self.albumName = albumName
self.initializeAlbum()
}
private func initializeAlbum() {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %@", self.albumName)
let collection: PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
if let firstObject: AnyObject = collection.firstObject {
self.albumExists = true
self.assetCollection = collection.firstObject as! PHAssetCollection
if let ac = self.assetCollection {
self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.assetCollection, options: nil)
}
println("\(self.albumName) album exists")
}
else {
var albumPlaceHolder: PHObjectPlaceholder!
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let request = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(self.albumName)
albumPlaceHolder = request.placeholderForCreatedAssetCollection
}, completionHandler: { (success: Bool, error: NSError!) in
self.albumExists = success
if success {
let collection = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([albumPlaceHolder.localIdentifier], options: nil)
self.assetCollection = collection.firstObject as! PHAssetCollection
if let ac = self.assetCollection {
self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.assetCollection, options: nil)
}
println("\(self.albumName) album made")
}
else {
println("Failed to create \(self.albumName) Album!!!!!!")
}
})
}
}
func savePhoto(image: UIImage, photoID: Int) {
let photoName = String(photoID)+".jpg"
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let assetPlaceholder = assetRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection, assets: self.photosAsset)
albumChangeRequest.addAssets([assetPlaceholder])
}, completionHandler: { (success: Bool, error: NSError!) in
print(success ? "image added" : "failed to add image")
})
}
func loadPhoto(photoID: Int64) -> UIImage {
let photoName = String(photoID)+".jpg"
return UIImage(named: "no_photo")!
}
func renameAlbum(newAlbumName: String) {
// need to create the new album and move all photos to that album then remove the old album
}
func reloadPhotos() {
if let ac = self.assetCollection {
self.photosAsset = PHAsset.fetchAssetsInAssetCollection(self.assetCollection, options: nil)
}
}
Upvotes: 3
Views: 6506
Reputation: 3698
Rather than 'naming' a file, you need to be taking a note of the localIdentifier
property of the asset you are creating. localIdentifier
is a persistent identifier (ie. it will be a consistent ID for the asset across restarts/reloads).
I've cobbled together some basic code that you could use to get the localIdentifier
when saving an image, and retrieve and image by a localIdentifier
. Hopefully this will get you going.
import UIKit
import Photos
class MRPhotosHelper {
var manager = PHImageManager.defaultManager()
func saveImageAsAsset(image: UIImage, completion: (localIdentifier:String?) -> Void) {
var imageIdentifier: String?
PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in
let changeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
let placeHolder = changeRequest.placeholderForCreatedAsset
imageIdentifier = placeHolder.localIdentifier
}, completionHandler: { (success, error) -> Void in
if success {
completion(localIdentifier: imageIdentifier)
} else {
completion(localIdentifier: nil)
}
})
}
func retrieveImageWithIdentifer(localIdentifier:String, completion: (image:UIImage?) -> Void) {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "mediaType == %d", PHAssetMediaType.Image.rawValue)
let fetchResults = PHAsset.fetchAssetsWithLocalIdentifiers([localIdentifier], options: fetchOptions)
if fetchResults.count > 0 {
if let imageAsset = fetchResults.objectAtIndex(0) as? PHAsset {
let requestOptions = PHImageRequestOptions()
requestOptions.deliveryMode = .HighQualityFormat
manager.requestImageForAsset(imageAsset, targetSize: PHImageManagerMaximumSize, contentMode: .AspectFill, options: requestOptions, resultHandler: { (image, info) -> Void in
completion(image: image)
})
} else {
completion(image: nil)
}
} else {
completion(image: nil)
}
}
}
You could then do something like this:
// get a reference to our helper
let helper = MRPhotosHelper()
// a var to store the localIdentifier for the image we save
var identifier:String?
// save the image to library
if let imageToSave = UIImage(named: "SomeImageName"){
helper.saveImageAsAsset(imageToSave, completion: { (localIdentifier) -> Void in
identifier = localIdentifier
})
}
// other stuff
// retrieve image from library at later date
if let identifier = identifier {
helper.retrieveImageWithIdentifer(identifier, completion: { (image) -> Void in
let retrievedImage = image
})
}
You may want to check that you are back on the main thread in the completion closures before using to update the UI.
Upvotes: 8