ios – 使用keyValueObservingExpectationForObject时的XCTest异常:keyPath:handler:

ios – 使用keyValueObservingExpectationForObject时的XCTest异常:keyPath:handler:,第1张

概述在我的单元测试中,我使用 – [XCTestCase keyValueObservingExpectationForObject:keyPath:handler:]方法以确保我的NSOperation完成,这是 code from my XCDYouTubeKit project: - (void) testStartingOnBackgroundThread{ XCDYouTubeVi 在我的单元测试中,我使用 – [XCTestCase keyvalueObservingExpectationForObject:keyPath:handler:]方法以确保我的NSOperation完成,这是 code from my XCDYouTubeKit project:
- (voID) testStartingOnBackgroundThread{    XCDYouTubeVIDeoOperation *operation = [[XCDYouTubeVIDeoOperation alloc] initWithVIDeoIDentifIEr:nil languageIDentifIEr:nil];    [self keyvalueObservingExpectationForObject:operation keyPath:@"isFinished" handler:^BOol(ID observedobject,NSDictionary *change)    {        XCTAssertNil([observedobject vIDeo]);        XCTAssertNotNil([observedobject error]);        return YES;    }];    dispatch_async(dispatch_get_global_queue(disPATCH_QUEUE_PRIORITY_DEFAulT,0),^{        XCTAssertFalse([NSThread isMainThread]);        [operation start];    });    [self waitForExpectationsWithTimeout:5 handler:nil];}

当我在Mac上本地运行它时,此测试总是通过,但有时它会因此错误而发生在fails on Travis:

Failed: caught “NSRangeException”,“Cannot remove an observer <_XCKVOExpectation 0x1001846c0> for the key path “isFinished” from <XCDYouTubeVIDeoOperation 0x1001b9510> because it is not registered as an observer.”

难道我做错了什么?

解决方法 您的代码是正确的,您在XCTest框架中发现了一个错误.这是一个深入的解释,如果您只是在寻找解决方法,可以跳到本答案的结尾.

当您调用keyvalueObservingExpectationForObject:keyPath:handler:时,会在引擎盖下创建_XCKVOExpectation对象.它负责观察您传递的对象/ keyPath.触发KVO通知后,将调用_safelyUnregister方法,这是删除观察者的位置.这是_safelyUnregister方法的(逆向工程)实现.

@implementation _XCKVOExpectation- (voID) _safelyUnregister{    if (!self.hasUnregistered)    {        [self.observedobject removeObserver:self forKeyPath:self.keyPath];        self.hasUnregistered = YES;    }}@end

在waitForExpectationsWithTimeout:handler:的末尾再次调用此方法,并且在释放_XCKVOExpectation对象时.请注意, *** 作在后台线程上终止,但测试在主线程上运行.所以你有一个竞争条件:如果在后台线程上将hasUnregistered属性设置为YES之前在主线程上调用了_safelyUnregister,则会删除观察者两次,导致无法删除观察者异常.

因此,为了解决此问题,您必须使用锁保护_safelyUnregister方法.这是一个代码片段供您在测试目标中进行编译,该代码片段将负责修复此错误.

#import <objc/runtime.h>__attribute__((constructor)) voID WorkaroundxcKVOExpectationUnregistrationRaceCondition(voID);__attribute__((constructor)) voID WorkaroundxcKVOExpectationUnregistrationRaceCondition(voID){    SEL _safelyUnregisterSEL = sel_getUID("_safelyUnregister");    Method safelyUnregister = class_getInstanceMethod(objc_lookUpClass("_XCKVOExpectation"),_safelyUnregisterSEL);    voID (*_safelyUnregisterIMP)(ID,SEL) = (__typeof__(_safelyUnregisterIMP))method_getImplementation(safelyUnregister);    method_setImplementation(safelyUnregister,imp_implementationWithBlock(^(ID self) {        @synchronized(self)        {            _safelyUnregisterIMP(self,_safelyUnregisterSEL);        }    }));}

编辑

这个BUG已经是fixed in Xcode 7 beta 4了.

总结

以上是内存溢出为你收集整理的ios – 使用keyValueObservingExpectationForObject时的XCTest异常:keyPath:handler:全部内容,希望文章能够帮你解决ios – 使用keyValueObservingExpectationForObject时的XCTest异常:keyPath:handler:所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1105434.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-28
下一篇2022-05-28

发表评论

登录后才能评论

评论列表(0条)

    保存