XCTest-Ausnahme bei Verwendung von keyValueObservingExpectationForObject: keyPath: handler:

8

In meinen Komponententests verwende ich die Methode -[XCTestCase keyValueObservingExpectationForObject:keyPath:handler:] , um sicherzustellen, dass meine NSOperation beendet ist, hier ist der Code aus meinem XCDYouTubeKit-Projekt :

%Vor%

Dieser Test wird immer ausgeführt, wenn ich ihn lokal auf meinem Mac ausführe, aber manchmal funktioniert auf Travis nicht mit diesem Fehler:

  

failed: hat "NSRangeException" abgefangen, "kann einen Beobachter & lt; _XCKVOExpectation 0x1001846c0 & gt; für den Schlüsselpfad" isFinished "von & lt; XCDYouTubeVideoOperation 0x1001b9510 & gt; nicht entfernen, da er nicht als Beobachter registriert ist."

Mache ich etwas falsch?

    
0xced 19.06.2015, 12:46
quelle

1 Antwort

10

Ihr Code ist korrekt, Sie haben einen Fehler im XCTest-Framework gefunden. Hier ist eine ausführliche Erklärung, Sie können zum Ende dieser Antwort springen, wenn Sie nur nach einem Workaround suchen.

Wenn Sie keyValueObservingExpectationForObject:keyPath:handler: aufrufen, wird ein _XCKVOExpectation -Objekt unter der Haube erstellt. Es ist dafür verantwortlich, das von Ihnen übergebene Objekt / keyPath zu beobachten. Sobald die KVO-Benachrichtigung ausgelöst wurde, wird die Methode _safelyUnregister aufgerufen. Hier wird der Beobachter entfernt. Hier ist die (reverse engineered) Implementierung der Methode _safelyUnregister .

%Vor%

Diese Methode wird am Ende von waitForExpectationsWithTimeout:handler: erneut aufgerufen und wenn das Objekt _XCKVOExpectation freigegeben wird. Beachten Sie, dass die Operation in einem Hintergrundthread endet, der Test jedoch im Hauptthread ausgeführt wird. Sie haben also eine Racebedingung: Wenn _safelyUnregister für den Hauptthread aufgerufen wird, bevor die hasUnregistered -Eigenschaft im Hintergrundthread auf YES gesetzt ist, wird der Beobachter zweimal entfernt, wodurch Einen Beobachter nicht entfernen Ausnahme.

Um dieses Problem zu umgehen, müssen Sie die Methode _safelyUnregister mit einer Sperre schützen. Hier ist ein Code-Snippet, das Sie in Ihr Testziel kompilieren können, das sich um die Behebung dieses Fehlers kümmert.

%Vor%

BEARBEITEN

Dieser Fehler wurde in Xcode 7 beta 4 behoben .

    
0xced 19.06.2015, 12:46
quelle