2012-05-17 15 views
10

Ein Teil meiner App hat einen Foto-Browser, der Apples Photos-App ähnelt, mit einem ersten View-Controller zum Durchsuchen von Fotominiaturen und einer Detailansicht, die beim Tippen auf ein Foto angezeigt wird.ALAssetsLibrary - Absturz nach dem Empfang von ALAssentsLibraryChangedNotification

Ich benutze ALAssentsLibrary, um auf Fotos zuzugreifen, und ich übergebe ein Array von ALAsset URLs an meine Detailansicht Controller, so dass Sie von einem Foto zum nächsten wischen können.

Alles funktioniert gut, bis ich eine ALAssetsLibraryChangedNotification erhalten, während von einem Foto zum anderen klauen (in der Detailansicht Controller), die oft in einem Crash-Ergebnisse:

MELDUNG: Die Objektbibliothek geändert // my eigene NSLog für, wenn die Benachrichtigung

Ladevermögen auftritt ... // mein eigenes NSLog, wenn ich starten Nachladen Vermögenswerte in die Thumbnail-Browser

Assertion fehlgeschlagen: (Größe == bytesread), Funktion - [ALAssetRepresentation _imageData], Datei /SourceCache/AssetsLibrary/MobileSlideShow-1373.58.1/Sources/ALAssetRepresentation.m, Linie 224.

Die spezifische Codezeile stürzt auf, ist in Aufruf [currentRep Metadaten] wie hier gezeigt:

- (void)someMethod { 
     NSURL *assetURL = [self.assetURLsArray objectAtIndex:index]; 
     ALAsset *currentAsset; 

     [self.assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) { 

      [self performSelectorInBackground:@selector(configureDetailViewForAsset:) withObject:asset]; 

      } failureBlock:^(NSError *error) { 
        NSLog(@"failed to retrieve asset: %@", error); 
     }]; 
} 

- (void)configureDetailViewForAsset:(ALAsset *)currentAsset { 
    ALAssetRepresentation *currentRep = [currentAsset defaultRepresentation]; 

    if (currentAsset != nil) { 
     // do some stuff 
    } 
    else { 
     NSLog(@"ERROR: currentAsset is nil"); 
    } 

    NSDictionary *metaDictionary; 
    if (currentRep != nil) { 
     metaDictionary = [currentRep metadata]; 

     // do some other stuff 
    } 
    else { 
     NSLog(@"ERROR: currentRep is nil"); 
    } 
} 

ich verstehe, dass, sobald eine Benachrichtigung empfangen wird, es alle Verweise auf ALAsset und ALAssetRepresentation Objekte entkräftet ... aber wie soll ich bin mit der Situation umgehen, wo es entkräftet etwas mitten im Versuch, darauf zuzugreifen?

Ich habe versucht, eine BOOL Einstellung richtig, wenn die Benachrichtigung empfangen wird vollständig abzubrechen und verhindern [currentRep Metadaten] jemals genannt zu werden, aber selbst das ist es nicht jedes Mal fangen:

if (self.receivedLibraryChangeNotification) { 
    NSLog(@"received library change notification, need to abort"); 
} 
else { 
    metaDictionary = [currentRep metadata]; 
} 

Ist Kann ich irgendetwas tun? An diesem Punkt bin ich fast bereit, die Verwendung des ALAssentsLibrary-Frameworks aufzugeben.

(beachten Sie diese ungelösten Thread im Forum Apple-Entwickler das gleiche Problem beschreibt: https://devforums.apple.com/message/604430)

Antwort

6

Es scheint, das Problem hier ist:

[self.assetsLibrary assetForURL:nextURL 

    resultBlock:^(ALAsset *asset) { 
     // You should do some stuff with asset at this scope 
     ALAssetRepresentation *currentRep = [asset defaultRepresentation]; 
     // Assume we have a property for that 
     self.assetRepresentationMetadata = [currentRep metadata]; 
     ... 
     // assume we have a method for that 
     [self updateAssetDetailsView]; 
    } 

    failureBlock:^(NSError *error) { 
     NSLog(@"failed to retrieve asset: %@", error); 
    }]; 

Sobald Sie Benutzer Asset bekommen haben es besser ist, Kopieren Sie Asset-Informationen, indem Sie die notwendigen Daten für Ihre Details Controller-Subviews bereitstellen oder indem Sie sie für die spätere Verwendung zwischenspeichern. Es kann hilfreich sein, um ALAsset-Ungültigkeitsprobleme zu vermeiden. Wenn die Benachrichtigung ALAssentsLibraryChangedNotification gesendet wird, müssen Sie möglicherweise den Details-Controller verwerfen und den Bibliotheksinhalt von Anfang an abfragen.

+1

Ich muss mehr testen ... aber das könnte geholfen haben. Es ist nicht in meinem Code oben gezeigt (da ich es für die Veröffentlichung hier vereinfachen wollte), aber [currentRep metadata] wurde in einem Hintergrundthread aufgerufen. Ich habe das geändert, um stattdessen das Metadatenwörterbuch innerhalb des resultBlocks "assetForURL", wie Sie es vorgeschlagen haben, zu finden, der sich zufällig im Hauptthread befindet. Es ist nicht so weit abgestürzt ... vielleicht ist die Metadata-Methode von ALAssetRepresentation nicht Thread-sicher? –

+0

Das Wichtigste ist, dass es Zeit braucht, um Medien mit 'assetForURL' zu erhalten. Daher können Sie außerhalb des Abschlussblocks nicht sicher sein, dass Sie Medien heruntergeladen haben ... – voromax

+0

Ich habe meine Frage aktualisiert, um genau zu zeigen, wie ich die "Metadaten" -Methode in einem Hintergrund-Thread aufgerufen habe. Basierend auf Ihrer Antwort habe ich es so geändert, dass ich zuerst das Metadatenwörterbuch abrufe und dann sowohl dieses als auch das Asset an meine configureDetailView-Methode übergebe. Nochmals, ich muss mehr testen, aber so weit so gut ... –

Verwandte Themen