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! :(
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.
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.
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.
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