Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save a big batch of photos using the new Photos framework?

I'm trying to save a big batch of photos into the Photos library using the new PHAssetChangeRequest class in iOS 8. Problem is, it looks like the daemon that saves the photos is itself crashing unexpectedly with a moderately large number of photos (I'm trying about 500). Anyone have any idea how to get around this limitation? Is it a memory usage problem in the daemon itself? It could also be a timeout limit on the change block, because in between the first 2 log statements below there's a not insignificant gap.

Shouldn't the assetsd daemon already be accounting for this use case since something like this is pretty much what the super complex model and design in the new Photos framework should have been able to handle? The documentation sample itself shows off the ability to save a photo.

Here's my code sample:

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    for (NSURL * url in fileURLs) {
        PHAssetChangeRequest * assetReq = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
    }
    NSLog(@"Added %d assets",fileURLs.count);
} completionHandler:^(BOOL success, NSError *error) {
     if (!success){
         NSLog(@"%@",error);
     }
}];

And this is what my output looks like:

... Added 501 assets
... Connection to assetsd was interrupted or assetsd died
... Error Domain=NSCocoaErrorDomain Code=-1 "The operation couldn’t be completed. (Cocoa error -1.)

I even tried the synchronous performChangesAndWait method in PHPhotoLibrary but it also has the same problem.

I'm open to suggestions / ideas, am stuck! :(

like image 988
Dhiraj Gupta Avatar asked Oct 03 '14 16:10

Dhiraj Gupta


People also ask

What is Photokit?

photokit Overview Photokit's online photo editor comes packed with tons of great features to help you perfect your photos. With just a few clicks, you can enhance photos, retouch portraits, remove backgrounds, apply effects, create photo collages and Crop, resize, rotate & apply basic edits with ease.

Which class from the photos framework allows developers to use representations of an image video or live photo stored on their device?

The PHLivePhotoView class provides a way to display Live Photos—pictures, taken on compatible hardware, that include motion and sound from the moments just before and after their capture. A Live Photo view provides the same interactive playback features found in the Photos app.


1 Answers

The idea is doing it in small batches. PHPhotoLibrary::performChanges submits change requests once all together, so even it was able to finish, you won't be able to get any updates on the progress from a delegate or block. The 2017 WWDC session "What's New in Photos APIs" came with a sample app "Creating Large Photo Libraries for Testing" that does exactly that. Each performChanges has 10 images submitted, and UI updates are from the completion block of the performChanges, with a Semaphore blocking the thread until one batch is processed. I'm posting the important code pieces here:

private func addPhotos() {
    let batchSize = min(photosToAdd, maxBatchSize)
    if batchSize <= 0 || !active {
        isAddingPhotos = false
        active = false
        return
    }

    workQueue.async {
        let fileURLs = self.generateImagesAndWriteToDisk(batchSize: batchSize)
        self.createPhotoLibraryAssets(with: fileURLs)

        DispatchQueue.main.async {
            self.addPhotos()
        }
    }
}

private func createPhotoLibraryAssets(with imageFileURLs: [URL]) {
    photoLibrarySemaphore.wait() // Wait for any ongoing photo library

    PHPhotoLibrary.shared().performChanges({
        let options = PHAssetResourceCreationOptions()
        options.shouldMoveFile = true
        for url in imageFileURLs {
            let creationRequest = PHAssetCreationRequest.forAsset()
            creationRequest.addResource(with: .photo, fileURL: url, options: options)
        }
    }) { (success, error) in
        if !success {
            print("Error saving asset to library:\(String(describing: error?.localizedDescription))")
        }
        self.photoLibrarySemaphore.signal()
    }
}

Above generateImagesAndWriteToDisk is the method you need to replace with what ever your method to return a batch of 10 photo urls or so. I personally don't like writing in recursion. The code can be easily changed to non-recursion style.

like image 101
X.Y. Avatar answered Nov 04 '22 03:11

X.Y.