2014-10-03 3 views
13

Ich versuche, eine große Menge von Fotos in der Bibliothek Fotos mit der neuen PHAssetChangeRequest Klasse in iOS 8 zu speichern. Problem ist, es sieht aus wie der Dämon, der die Fotos speichert unerwartet unerwartet mit einer moderaten Anzahl von Fotos (Ich versuche etwa 500). Hat jemand eine Idee, wie man diese Einschränkung umgehen kann? Ist es ein Speicherproblem im Daemon selbst? Es könnte auch ein Timeout-Limit für den Change-Block sein, da zwischen den ersten beiden Log-Statements darunter eine nicht unbedeutende Lücke liegt.Speichern Sie eine große Anzahl von Fotos mit dem neuen Photos-Framework?

Sollte nicht die assetsd Daemon bereits für diesen Anwendungsfall werden Buchhaltung, da so etwas wie dies ist ziemlich viel, was das Superkomplex Modell und Design im neuen Foto Rahmen sollen umgehen kann? Das Dokumentationsbeispiel selbst zeigt die Möglichkeit, ein Foto zu speichern.

Hier ist mein Codebeispiel:

[[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); 
    } 
}]; 

Und das ist, was meine Ausgabe wie folgt aussieht:

... 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.) 

Ich habe sogar versucht die synchrone performChangesAndWait Methode in PHPhotoLibrary aber es hat auch das gleiche Problem.

Ich bin offen für Vorschläge/Ideen, bin fest! :(

+0

Ich stoße auf ein ähnliches Problem.Ich speichere 4 Bilder, und es funktioniert, aber wenn ich versuche, 4 Bilder erneut zu speichern, um die vorhandenen zu ersetzen, erhalte ich diesen Fehler. Wenn ich eine Lösung gefunden habe, melde ich mich bei Ihnen. – Aggressor

+0

@Aggressor Ich sehe keine Möglichkeit, vorhandene Fotos in der Bilderbibliothek zu "ersetzen". Du könntest sie wieder löschen und hinzufügen, nehme ich an. –

+0

Dieser Fehler scheint von der Speicherüberlastung zu stammen. Ich habe die Dateigröße des UIImage reduziert und das Problem behoben. Ich kann Code schreiben, wenn Sie ihn sehen müssen. – Aggressor

Antwort

-1

Dies ist nicht wirklich eine Lösung für diese Frage, aber ist es eine Abhilfe. Sie noch die alte ALAssetsLibrary verwenden können erfolgreich Dateien auf die Camera Roll/Fotos App zu speichern.

ALAssetsLibrary* lib = [[ALAssetsLibrary alloc] init]; 
[lib writeImageDataToSavedPhotosAlbum:imageData metadata:nil 
         completionBlock:^(NSURL *assetURL, NSError *error) 
{ 
    // start saving your next image 
}]; 

Es Es empfiehlt sich auch, eine einzelne Instanz der AssetsLibrary zu verwenden, wenn Sie alle zu speichernden Fotos durchgehen möchten.Wollen Sie wahrscheinlich auch warten, bis die erste Bildspeicherung abgeschlossen ist, um die nächste zu speichern.

Sie können dann die resulting assetURL zu einem PHAsset bei Bedarf:

+ (PHFetchResult *)fetchAssetsWithALAssetURLs:(NSArray *)assetURLs 
            options:(PHFetchOptions *)options 
0

Bei der Verarbeitung einer großen Anzahl von Bildern auf dem Gerät müssen Sie selbst in den modernen ARC-Zeiten sehr vorsichtig mit der Speicherverwaltung umgehen. Ich hatte eine große Anzahl von Bildern zu verarbeiten (50+ mit Größenanpassung) und am Ende wählte ich den CGImageSourceCreateThumbnailAtIndex() as suggested by the answer here. Es verwendet ImageIO, das sehr effizient sein soll. Die einzige Frage, die ich noch hatte, ist, dass es aus irgendeinem Grunde immer noch in dem Speicher hängen würde, wenn ich meine for-Schleife in einer @autoreleasepool {}

for (ALAsset *asset in assets) { 
     @autoreleasepool { 
      resizedImage = [self thumbnailForAsset:asset maxPixelSize:JPEG_MAX_DIMENSION]; 
     // do stuff here 
    } 
} 
1

statt creationRequestForAssetFromImageAtFileURL gewickelt, habe ich diese Methode und es funktionierte perfekt 10 Bilder (dieser Teil des Codes wird in einem tableView:cellForRowAtIndexPath: wiederholt)

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); 
     } 
}]; 
0

Die Idee, es in kleinen Chargen tut. PHPhotoLibrary::performChanges sendet einmal alle Änderungsanforderungen zusammen, so dass es selbst dann, wenn es abgeschlossen werden konnte, keine Aktualisierungen des Fortschritts von einem Delegaten oder Block erhalten kann. Die 2017 WWDC Sitzung "What's New in Photos APIs" kam mit einer Beispiel-App "Creating Large Photo Libraries for Testing", die genau das tut. Jede performChanges hat 10 Bilder eingereicht, und UI-Updates sind aus dem Abschlussblock der performChanges, mit einem Semaphore blockiert den Thread, bis eine Charge verarbeitet wird.Ich poste die wichtigen Code Stücke hier:

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() 
    } 
} 

Oberhalb generateImagesAndWriteToDisk die Methode ist, dass Sie mit dem, was auch immer Ihre Methode ersetzen müssen eine Charge von 10 Foto Urls oder so zurückzukehren. Ich persönlich mag es nicht, in Rekursion zu schreiben. Der Code kann leicht in Nicht-Rekursionsstil geändert werden.