ブロックと GCD/NSOperation の練習をしようと思ってこのプロジェクトAsync-objcを書いたのですが、ユニットテストでテストしようとすると、常に 'double free' エラーが発生し、あってはならないことだと思いましたARC モードではこのようなエラーになります。
ここにコードがあります
- (void)each:(NSArray *)items iterator:(callbackEach)iterator complete:(callbackWithError)complete {
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
if (!items || items.count == 0) {
complete(nil);
return;
}
callbackWithError __block completeOnce = complete;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSLog(@"start operations %@", queue);
[queue setMaxConcurrentOperationCount:kMaxConcurrentOperationCount];
NSInteger __block count = 0;
for (id item in items) {
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
iterator(item, ^(NSError *error) {
if (error) {
completeOnce(error);
completeOnce = nil;
} else {
count++;
if (count >= items.count) {
completeOnce(nil);
completeOnce = nil;
}
}
});
}];
[queue addOperation:op];
}
[queue waitUntilAllOperationsAreFinished];
NSLog(@"all operations are down %@", queue);
}];
[_mainQueue addOperation:blockOp];
}
これはテストコードです:
- (void)testEachWithBigData {
BOOL __block completed = false;
NSMutableArray *items = [NSMutableArray arrayWithCapacity:100];
for (int i = 1; i < 10000; ++i) {
[items addObject:[NSString stringWithFormat:@"%d", i]];
}
NSMutableArray *result = [NSMutableArray arrayWithCapacity:100];
[_async each:items
iterator:^(id item, callbackWithError callback) {
//NSLog(@"======item %@", item);
NSNumber *num = [NSNumber numberWithInt:[item integerValue]];
//NSLog(@"number %@", num);
[result addObject:num];
callback(nil);
}
complete:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
STAssertNil(error, @"there should be no error");
[result sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSNumber *num1 = (NSNumber *)obj1;
NSNumber *num2 = (NSNumber *)obj2;
if ([num1 integerValue] > [num2 integerValue]) {
return NSOrderedDescending;
} else if ([num1 integerValue] < [num2 integerValue]) {
return NSOrderedAscending;
}
return NSOrderedSame;
}];
NSInteger index = 1;
for (NSNumber *num in result) {
STAssertEquals(index, [num integerValue], @"the value should be ordered");
index++;
}
completed = YES;
});
}
];
NSDate *until = [NSDate dateWithTimeIntervalSinceNow:10];
while (!completed && [until timeIntervalSinceNow] > 0) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:until];
}
}
エラーを再現できなかった場合は、テスト項目数を 10000 に増やします。
for (int i = 1; i < 10000; ++i) {
[items addObject:[NSString stringWithFormat:@"%d", i]];
}
NSLog()をコメントして から、Command + U で単体テストを実行します
エラー メッセージは次のとおりです。
otest(11209,0xb0115000) malloc: * オブジェクト 0x41dcc00 のエラー: 解放されるポインターが割り当てられませんでした *デバッグするために malloc_error_break にブレークポイントを設定します
今回は「ダブルフリー」エラーを再現できません