0

I want to move an asset from one album to another. But I could only find information on creating and deleting assets. The reason I want to move instead of creating a new one and deleting the old copy is, I want to preserve the bits of data like the localIdentifier of the asset. If I recreate an asset in another album, it will be assigned a new localIdentifier, am I right?

But it seems it's not possible. So I resorted to copying the asset at least. But it's giving me trouble as well.

Here's my code.

func copyAsset() {
    if let assets = getAssetsFromCollection(collectionTitle: "Old") {
        if getAssetColection("New") == nil {
            createCollection("New") { collection in
                if let collection = collection {
                    print("Collection created")
                    self.copyAssetsToCollection(assets, toCollection: collection)
                }
            }
        }
    }
}

/**
 Copy assets to album.

 - parameter assets:     Array of assets to copy.
 - parameter collection: The collection where the assets need to be copied.
 */
func copyAssetsToCollection(assets: [PHAsset], toCollection collection: PHAssetCollection) {
    PHPhotoLibrary.sharedPhotoLibrary().performChanges({
        let asset = assets.first!
        print(asset.localIdentifier)
        let assetChangeRequest = PHAssetChangeRequest(forAsset: asset)
        let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset!

        let collectionChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: collection)!
        collectionChangeRequest.addAssets([assetPlaceholder])
    }, completionHandler: { success, error in
        if success {
            print("Photo copied to collection")
        } else {
            if let error = error {
                print("Error adding photos to collection: \(error.code) - \(error.localizedDescription)")
            }
        }
    })
}

/**
 Retrieve the album for the given title.

 - parameter title: Album title.

 - returns: Album if it exists. nil if it doesn't.
 */
func getAssetColection(title: String) -> PHAssetCollection? {
    let fetchOptions = PHFetchOptions()
    fetchOptions.predicate = NSPredicate(format: "title ==[cd] %@", title)
    if let collection = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .AlbumRegular, options: fetchOptions).firstObject {
        return collection as? PHAssetCollection
    }
    return nil
}

/**
 Get assets from a given album.

 - parameter title: Album title.

 - returns: An array of assets if they exist. nil if they don't.
 */
func getAssetsFromCollection(collectionTitle title: String) -> [PHAsset]? {
    var assets = [PHAsset]()
    if let collection = getAssetColection(title) {
        let fetchOptions = PHFetchOptions()
        fetchOptions.predicate = NSPredicate(format: "mediaType == %d", PHAssetMediaType.Image.rawValue)
        let fetchResult = PHAsset.fetchAssetsInAssetCollection(collection, options: fetchOptions)
        fetchResult.enumerateObjectsUsingBlock { object, index, stop in
            if let asset = object as? PHAsset {
                assets.append(asset)
            }
        }
        return assets
    }
    return nil
}

/**
 Create an album in Photos app.

 - parameter title:      Album title.
 - parameter completion: Album if successfully created. nil if it fails.
 */
func createCollection(title: String, completion: (collection: PHAssetCollection?) -> ()) {
    var albumPlaceholder: PHObjectPlaceholder!
    PHPhotoLibrary.sharedPhotoLibrary().performChanges({
        let request = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(title)
        albumPlaceholder = request.placeholderForCreatedAssetCollection
    }, completionHandler: { success, error in
        if success {
            let fetchResult = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([albumPlaceholder.localIdentifier], options: nil)
            completion(collection: fetchResult.firstObject as? PHAssetCollection)
        } else {
            if let error = error {
                print("Failed to create album: \(title) in Photos app: \(error.code) - \(error.localizedDescription)")
                completion(collection: nil)
            }
        }
    })
}

The app crashes at the line let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset! for finding nil value for the placeholderForCreatedAsset. Which means PHAssetChangeRequest(forAsset: asset) can only be used to changing an asset's metadata and not duplicating it.

Is there any other way to do this? Any workaround or hack? I'll really appreciate any help.

Isuru
  • 30,617
  • 60
  • 187
  • 303

1 Answers1

1

There is nothing like copying an asset from one album to another: In the iOS Photo Library all original photos/videos are located in "All Photos"/"Camera Roll". Albums contain only references to the original photo/video located in "All Photos/Camera Roll". This means you can assign one photo to n-Albums. To manage those assignments please have a look at the PHAssetCollectionChangeRequest class. To add one or several photos/video at an album use the addAssets:, to remove assets from an album use the removeAssets:method.

holtmann
  • 6,043
  • 32
  • 44