由于dispatch_once导致XCTest失败的解决方法?

时间:2014-04-26 05:40:09

标签: objective-c xcode xctest

如果多个测试需要运行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 个答案:

答案 0 :(得分:2)

测试是在get方法中暴露内存管理问题。由于arrayWithObjects:返回一个自动释放的对象,因此在下一次弹出自动释放池时,在MRC下指向的数组_get将被释放。要解决这个问题,需要保留数组,方法是使用initWithObjects:分配数组,或者向arrayWithObjects:返回的对象发送保留消息。