2017-12-24 3 views
0

Meine app verwendet die folgende Funktion eine Reihe von benutzerdefinierten Objekte serialise (nur relevante Code dargestellt wird):Absturz beim Datenarchivierung von NSKeyedArchiver

class func serializeShoppingLocations(buyLocations: Set<ShoppingLocation>) -> Data { 
    #if os(iOS) 
     NSKeyedArchiver.setClassName("ShoppingLocation", for: ShoppingListIOS.ShoppingLocation.self) 
    #elseif os(watchOS) 
     NSKeyedArchiver.setClassName("ShoppingLocation", for: ShoppingListWatch.ShoppingLocation.self) 
    #endif 
    let data = NSKeyedArchiver.archivedData(withRootObject: buyLocations) 
    return data 
} 

Die bedingte Kompilierung für die iOS und watchOS Ziele erforderlich ist, um damit beide Ziele später die serialisierten Daten dearchivieren können, selbst wenn sie vom anderen Ziel archiviert wurden.

ShoppingLocation übernimmt das Protokoll NSCoding und erbt von NSObject.

Dieser Code stürzt bei der let data = … Anweisung mit EXC_BAD_ACCESS (code=1, address=0x0) ab.

Ich weiß, dass der Fehler wahrscheinlich darauf hinweist, dass ein nicht vorhandenes Objekt verwiesen wird. Die Variable buyLocations ist jedoch vorhanden, und ich kann den Wert im Debugger einschließlich aller Werte der Objekte im Satz ausgeben.

Der Stack-Trace ist:
enter image description here

Der Stack-Trace zeigt an, dass die Archivierungs die NSSet zu archivieren startet und versucht, eines der Elemente des Satzes zu archivieren, aber setObjectForKey in der internen wandelbar Wörterbuch ausfällt.

Was könnte der Grund sein?

EDIT:

Während der weitere Tests I, dass der Crash realisiert geschieht immer dann, wenn mindestens 2 Fäden der app aktiv sind.
Insbesondere fand ich eine Situation, in der ein Faden (rot in Xcode) abgestürzt ist an einem unterschiedlichen Befehl von dem oben erwähnten:

let dataBlob = NSKeyedArchiver.archivedData(withRootObject: shoppingItem.buyLocations) 

und der andere Faden an der Instruktion gestoppt oben (in Xcode grün) erwähnt:

let data = NSKeyedArchiver.archivedData(withRootObject: buyLocations) 

Könnte es sein, dass NSKeyedArchiver nicht Thread-sicher ist?

+1

stellen Sie sicher, dass ShoppingLocation von NSObject erbt –

+0

@Leo Dabus Danke für den Hinweis, aber ShoppingLocation erbt von NSObject. Ich werde meine Frage aktualisieren. –

Antwort

0

Mein Problem ist in der Tat, wie vermutet wird, durch mehrere Threads von unsynchronisierten Zugriffe verursacht:

Ein NSArchiver geht durch ein Objektdiagramm, auf das Wurzelobjekt beginnt und Archiven auf dem Weg jedes Objekt, das es trifft.
Um ein korrektes Archiv zu erstellen, ist es daher erforderlich, dass das Objektdiagramm nicht mutiert wird, bis der Archivierer beendet wird.

In einer Singlethread-Anwendung wird dies automatisch garantiert.
In einer Multithreadanwendung, in der mehr als 1 Thread das Objektdiagramm mutieren kann, muss der Programmierer dafür sorgen, dass der Archivierer keine Möglichkeit hat, andere Threads daran zu hindern, das Stammobjekt zu mutieren. (Wenn z. B. der Archivierer zuerst eine tiefe Kopie des Objektgraphen erstellen und dann die Kopie archivieren würde, könnte das Objektgraph während der tiefen Kopie mutiert werden).

Es ist daher erforderlich, alle Zugriffe auf den Objektgraph, z. indem Sie sie in einer seriellen Zugriffswarteschlange ausführen.