我正在尝试使用iOS 8中的新PHAssetChangeRequest
类将大量照片保存到照片库中。问题是,看起来保存照片的守护程序本身意外地崩溃了大量的照片(我正在尝试大约500张)。任何人都知道如何解决这个限制?这是守护进程本身的内存使用问题吗?它也可能是更改块的超时限制,因为在下面的前两个日志语句之间存在不无关紧要的差距。
assetsd
守护进程不应该已经考虑到这个用例,因为类似这样的东西几乎就是新的Photos框架中的超复杂模型和设计应该能够处理?文档示例本身展示了保存照片的功能。
这是我的代码示例:
[[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);
}
}];
这就是我的输出:
... 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.)
我甚至尝试了performChangesAndWait
中的同步PHPhotoLibrary
方法,但它也存在同样的问题。
我对建议/想法持开放态度,我被困住了! :(
答案 0 :(得分:1)
而不是creationRequestForAssetFromImageAtFileURL
,我使用了这种方法,它适用于10张图片(这部分代码在tableView:cellForRowAtIndexPath:
中重复)
UIImage *thisImage=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@",serverInfo,self.URLs[indexPath.row]]]]];
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest * assetReq = [PHAssetChangeRequest creationRequestForAssetFromImage:thisImage];
NSLog(@"Added %ld assets",(long)indexPath.row);
} completionHandler:^(BOOL success, NSError *error) {
if (!success){
NSLog(@"%@",error);
}
}];
答案 1 :(得分:1)
这个想法是小批量做的。 PHPhotoLibrary::performChanges
一起提交更改请求,因此即使它能够完成,您也无法从委托或块中获取有关进度的任何更新。 2017年WWDC会议"What's New in Photos APIs"附带了一个示例应用程序“Creating Large Photo Libraries for Testing”。每个performChanges
提交了10个图像,UI更新来自performChanges
的完成块,信号量阻塞线程直到处理完一个批处理。我在这里发布了重要的代码:
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()
}
}
以上generateImagesAndWriteToDisk
是您需要用您的方法替换以返回一批10张照片网址的方法。我个人不喜欢写递归。代码可以很容易地更改为非递归样式。
答案 2 :(得分:0)
在设备上处理大量图像时,即使在ARC的现代,您也必须非常小心内存管理。我有大量要处理的图像(50+用于调整大小)并最终选择了CGImageSourceCreateThumbnailAtIndex()as suggested by the answer here。它使用ImageIO,它应该是非常有效的。我剩下的唯一问题是,由于某种原因,除非我将我的for循环包装在@autoreleasepool {}
中,否则它仍会依赖于内存for (ALAsset *asset in assets) {
@autoreleasepool {
resizedImage = [self thumbnailForAsset:asset maxPixelSize:JPEG_MAX_DIMENSION];
// do stuff here
}
}
答案 3 :(得分:-1)
这不是这个问题的真正解决方案,但它是一种解决方法。您仍然可以使用旧的ALAssetsLibrary将文件成功保存到相机胶卷/照片应用程序。
ALAssetsLibrary* lib = [[ALAssetsLibrary alloc] init];
[lib writeImageDataToSavedPhotosAlbum:imageData metadata:nil
completionBlock:^(NSURL *assetURL, NSError *error)
{
// start saving your next image
}];
在循环浏览要保存的所有照片时,还建议使用AssetsLibrary的单个实例。您可能还想等待第一个图像保存完成以开始保存下一个图像。
然后,您可以根据需要将生成的assetURL转换为PHAsset:
+ (PHFetchResult *)fetchAssetsWithALAssetURLs:(NSArray *)assetURLs
options:(PHFetchOptions *)options