I have a custom album in which my app saves picture from camera. I am wondering if there is a way I can create folders inside my album so I can stack certain images inside it?
ANSWER
As fellow members mentioned, sadly there is no way you can create a folder inside album.
You should try code below. It's Swift 3.0 syntaxe. :)
import Foundation
import Photos
class CustomPhotoAlbum: NSObject {
static let albumName = "Album Name"
static let sharedInstance = CustomPhotoAlbum()
var assetCollection: PHAssetCollection!
override init() {
super.init()
if let assetCollection = fetchAssetCollectionForAlbum() {
self.assetCollection = assetCollection
return
}
if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.authorized {
PHPhotoLibrary.requestAuthorization({ (status: PHAuthorizationStatus) -> Void in
()
})
}
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
self.createAlbum()
} else {
PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
}
}
func requestAuthorizationHandler(status: PHAuthorizationStatus) {
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
// ideally this ensures the creation of the photo album even if authorization wasn't prompted till after init was done
print("trying again to create the album")
self.createAlbum()
} else {
print("should really prompt the user to let them know it's failed")
}
}
func createAlbum() {
PHPhotoLibrary.shared().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: CustomPhotoAlbum.albumName) // create an asset collection with the album name
}) { success, error in
if success {
self.assetCollection = self.fetchAssetCollectionForAlbum()
} else {
print("error \(error)")
}
}
}
func fetchAssetCollectionForAlbum() -> PHAssetCollection? {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %@", CustomPhotoAlbum.albumName)
let collection = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let _: AnyObject = collection.firstObject {
return collection.firstObject
}
return nil
}
func save(image: UIImage) {
if assetCollection == nil {
return // if there was an error upstream, skip the save
}
PHPhotoLibrary.shared().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection)
let enumeration: NSArray = [assetPlaceHolder!]
albumChangeRequest!.addAssets(enumeration)
}, completionHandler: nil)
}
}
You can add albums within folders in the user's Photos Albums. I just figured out how to do it, today:
import Photos
class PhotoManager {
static let instance = PhotoManager()
var folder: PHCollectionList?
/// Fetches an existing folder with the specified identifier or creates one with the specified name
func fetchFolderWithIdentifier(_ identifier: String, name: String) {
let fetchResult = PHCollectionList.fetchCollectionLists(withLocalIdentifiers: [identifier], options: nil)
guard let folder = fetchResult.firstObject else {
createFolderWithName(name)
return
}
self.folder = folder
}
/// Creates a folder with the specified name
private func createFolderWithName(_ name: String) {
var placeholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
let changeRequest = PHCollectionListChangeRequest.creationRequestForCollectionList(withTitle: name)
placeholder = changeRequest.placeholderForCreatedCollectionList
}) { (success, error) in
guard let placeholder = placeholder else { return }
let fetchResult = PHCollectionList.fetchCollectionLists(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
guard let folder = fetchResult.firstObject else { return }
self.folder = folder
}
}
/// Creates an album with the specified name
private func createAlbumWithName(_ name: String, completion: @escaping (PHAssetCollection?) -> Void) {
guard let folder = folder else {
completion(nil)
return
}
var placeholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
let listRequest = PHCollectionListChangeRequest(for: folder)
let createAlbumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: name)
listRequest?.addChildCollections([createAlbumRequest.placeholderForCreatedAssetCollection] as NSArray)
placeholder = createAlbumRequest.placeholderForCreatedAssetCollection
}) { (success, error) in
guard let placeholder = placeholder else {
completion(nil)
return
}
let fetchResult = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
let album = fetchResult.firstObject
completion(album)
}
}
/// Saves the image to a new album with the specified name
func saveImageToAlbumInRootFolder(_ albumName: String, image: UIImage?, completion: @escaping (Error?) -> Void) {
createAlbumWithName(albumName) { (album) in
guard let album = album else {
return
}
PHPhotoLibrary.shared().performChanges({
let albumChangeRequest = PHAssetCollectionChangeRequest(for: album)
let createAssetRequest = PHAssetChangeRequest.creationRequestForAsset(from: image!)
let photoPlaceholder = createAssetRequest.placeholderForCreatedAsset!
albumChangeRequest?.addAssets([photoPlaceholder] as NSArray)
}, completionHandler: { (success, error) in
if success {
completion(nil)
} else if let error = error {
// Failed with error
} else {
// Failed with no error
}
})
}
}
}
This allows you to do something like this:
let defaults = UserDefaults.standard
let identifier = defaults.string(forKey: "myFolder")!
PhotoManager.instance.fetchFolderWithIdentifier(identifier, name: "My Folder")
PhotoManager.instance.saveImageToAlbumInRootFolder("My Album", image: UIImage(named: "my_image")) { (error) in
// Handle error
}
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