
- (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:所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)