由于 dispatch_once 导致 XCTest 失败的解决方法?
Posted
技术标签:
【中文标题】由于 dispatch_once 导致 XCTest 失败的解决方法?【英文标题】:Workaround for XCTest failures due to dispatch_once? 【发布时间】:2014-04-26 05:40:09 【问题描述】:如果多个测试需要运行 dispatch_once(),那么只有一个测试通过。
这是一个问题示例(非 ARC 代码):
#import <XCTest/XCTest.h>
@interface TestBrokenDispatchOnce : XCTestCase
@end
@implementation TestBrokenDispatchOnce
+(NSArray*) get
static NSArray* _get;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
_get=[NSArray arrayWithObjects:@(1),@(2),nil];
);
return _get;
- (void)testOne
for(NSNumber* n in [[self class] get])
NSLog(@"%@",n);
XCTAssertTrue(YES, @"pass");
- (void)testTwo
// will die here with access exception
for(NSNumber* n in [[self class] get])
NSLog(@"%@",n);
XCTAssertTrue(YES, @"pass");
@end
每个单独运行的测试用例都会通过,但如果两个都运行,第二个就会失败。
我看到的实际问题是针对使用 dispatch_once 对数组进行延迟初始化的(非 ARC 库)进行测试,但失败与这个最小示例相同。我猜测 XCTest 框架正在释放一些内存池,因此 NSArray 被释放,但静态保持初始化。
除了在测试中重置 onceToken 之外,还有其他解决方案吗?
【问题讨论】:
【参考方案1】:测试暴露了get
方法中的内存管理问题。由于arrayWithObjects:
返回一个自动释放对象,因此在MRC 下,_get
指向的数组在下次弹出自动释放池时被释放。要解决此问题,需要保留数组,方法是使用initWithObjects:
分配它或向arrayWithObjects:
返回的对象发送保留消息。
【讨论】:
谢谢。将保留附加到 arrayWithObjects 固定的东西。以上是关于由于 dispatch_once 导致 XCTest 失败的解决方法?的主要内容,如果未能解决你的问题,请参考以下文章