2015-02-18 3 views
8

Diese Codezeile wird in meiner awakeFromFetch Methode aufgerufen, die sich in einem benutzerdefinierten verwalteten Objekt befindet, das NSManagedObject implementiert. Diese Zeile ruft insbesondere meine Singleton Network Manager-Klasse namens sharedManager auf.Versand einmalig (dispatch_once) singleton friert/sperrt in Ziel c

[self setSync:(![[WKNetworkManager sharedManager] objectHasPendingRequests:self.objectID]) ]; 

Der dispatch_once Block wird wie unten gezeigt getroffen. Beachten Sie, dass es in einer guten Art und Weise durchgeführt wird, wie here gezeigt wird:

enter image description here

Der dispatch_once Anruf geht dann once.h und hier friert es rechts auf die markierte Zeile:

dipatch_once deeper

Hier

ist der Stack-Trace:

stack trace

All dies geschieht, wenn Sie versuchen, eine zuvor gespeicherte Netzwerkwarteschlangendatei zu laden. Die Anwendung wird vollständig geschlossen, um zu speichern und dann erneut gestartet, und dann erfolgt das Einfrieren/Sperren.

Ich habe sogar versucht, diesen Code stattdessen zu verwenden, um das Problem zu lösen, wie es vorgeschlagen wird here, und es hat nicht funktioniert. Aber es wäre wahrscheinlich egal, dies zu ändern, da mein ursprünglicher dispatch_once-Code lange gut funktioniert hat. Es ist nur in diesem speziellen Fall.

if ([NSThread isMainThread]) 
{ 
    dispatch_once(&onceToken, ^{ 
    stack = [[KACoreDataStack alloc] init];}); 
} 
else 
{ 
    dispatch_sync(dispatch_get_main_queue(), ^{ 
    dispatch_once(&onceToken, ^{ 
    stack = [[KACoreDataStack alloc] init];}); 
}); 
} 

Bisher das sind meine Quellen für die Fehlersuche, diese Art von Problem:

Danke für Ihre Hilfe!

Antwort

0

Dank der Hilfe von alexcurylo konnte das Problem mit dem Job loadFromDisk behoben werden. Damit die Leute nicht verwirrt sind, stehe ich mit dem folgenden Code in der Warteschlange eines Jobs, der ein Array (das als eine gespeicherte Warteschlange von Benutzeranforderungen fungiert) von der Festplatte lädt. Sie könnten einen Auftrag in die Warteschlange stellen, z. B. Laden von Bildern usw. Der folgende Code in meiner sharedManager-Klasse (Laden von Festplatte wird aufgerufen) funktioniert wie hier gezeigt:

-(void) loadQueueFromFileByQueueing 
{ 
    //Create a Queue 
    /* Note that fileStrQueue should be added to the .h file as NSOperationQueue *fileStrQueue;*/ 
    fileStrQueue = [[NSOperationQueue alloc] init]; 

    //Create an operation which will invoke method loadQueueFromDisk 
    NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadQueueFromDisk) object:nil]; 

    //Add this operation to the queue 
    [fileStrQueue addOperation:operation]; 

    //Releasing the above operation as it is already retained by the queue. 
    // [operation release]; // If you are using ARC, this won't be necessary 
} 
6

Verdammter Sohn, das ist eine gute Aufgabe der Frage.

Das Problem hier ist, dass rekursive Aufrufe von dispatch_once Deadlock wird. Wenn Sie genaue Details wünschen, you can find them with the source here. Sie müssen also neu schreiben, um das zu vermeiden.

Meine Meinung ist, dass es einen architektonischen Fehltritt mit allem, was zu dieser -loadQueueFromDisk Anruf führt. Sie tun absolut nicht wollen etwas tun, das als möglicherweise unbegrenzt in der Ausführungszeit als gehen und Laden von etwas von der Festplatte in einem dispatch_once. Was Sie tun möchten, ist das absolute Minimum, um ein adressierbares Singleton zu erstellen und wieder herauszukommen. Geben Sie dann einen internen Status von "Initializing" ein, und senden Sie das Disk-Loading-Zeug irgendwo in eine nicht blockierende Warteschlange.Auf diese Weise kann alles, was nicht von dem von der Festplatte geladenen Material abhängt, fortgesetzt werden, und alles, was von dem von der Platte geladenen Material abhängt, kann sich der Warteschlange hinzufügen oder alle paar hundert Millisekunden nachsehen wenn es sich noch in einem "initialisierten" Zustand befindet oder etwas in dieser Richtung.

+0

Vielen Dank! Ich glaube, Sie haben etwas mit Architektur zu tun. Diese ganze Lade von der Disk-Sache wird hinzugefügt, nachdem die App entworfen wurde und offensichtlich spielt es nicht nett damit. WKNetworkManager (sharedManager) ruft '[self loadQueueFromDisk];'. Durch das Erzeugen der decodierten Objekte lösen diese Objektinitialisierungen wiederum Aufrufe von sharedManager aus. Das könnte sicherlich problematisch sein. Die verknüpfte Lösung sieht sperrig aus. Denken Sie, eine Block-Anweisung von loadQueueFromDisk zu erstellen, um die Aufgabe an einen anderen Thread zu delegieren? – Marcel

+0

Wenn Sie die Frage mögen, upvote es! – Raspu

+1

Nun, Core Data und Threading, das kann schnell kompliziert werden. Meine erste Neigung zur Kerndaten-Initialisierung ist, sie in die GCD-Warteschlange mit niedriger Priorität zu versetzen 'dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_LOW, 0),^{[self loadQueueFromDisk];}); so wird es einmal behandelt Warteschlangen mit hoher und normaler Priorität sind leer. Das ist wahrscheinlich das erwünschte Verhalten beim Start. –