Different behavior between enumerateObjectsUsingBlock: and for (in)

Give this code

NSMutableArray *array = [NSMutableArray new];
for (int i = 0; i < 10000; i++) {
    [array addObject:@(i)];
}

queue1 = dispatch_queue_create("com.test_enumaration.1", DISPATCH_QUEUE_CONCURRENT);
queue2 = dispatch_queue_create("com.test_enumaration.2", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue1, ^{
    int idx = 0;
    for (NSNumber *obj in array) {
        NSLog(@"[%d] %@", idx, obj);
        idx++;
    }
});

double delayInSeconds = 0.3;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, queue2, ^(void){
    [array removeObjectAtIndex:9000];
    NSLog(@"----");
});

I expect this code to fail because at some point the block sent to queue2will execute at the same time as the enumeration, and this will lead to the assertion that you cannot mutate the array when enumerating. Indeed, this is what happens.

The interesting part is replacing for ( in )withenumerateObjectsUsingBlock:

NSMutableArray *array = [NSMutableArray new];
for (int i = 0; i < 10000; i++) {
    [array addObject:@(i)];
}

queue1 = dispatch_queue_create("com.test_enumaration.1", DISPATCH_QUEUE_CONCURRENT);
queue2 = dispatch_queue_create("com.test_enumaration.2", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue1, ^{
    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"[%d] %@",idx, obj);
    }];
});

double delayInSeconds = 0.3;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, queue2, ^(void){
    [array removeObjectAtIndex:9000];
    NSLog(@"----");
});

In all my tests, the block that deletes the object is executed in the middle of the enumeration (I see the imprint @ "----"), and the interesting thing is that the enumeration behaves correctly to print [8999] 8999and then [9000] 9001.

In this case, the array is mutated during enumeration, without raising any statement. Is this intended behavior? If so, why? Did I miss something?

+4
1

go-to ... . , for(in) enumerateObjectsUsingBlock:, .

, . NSMutableArray , ; 100 , . , ( , iOS) . . , ; , , .

, . for(in). -, enumerateObjectsUsingBlock: , . , ... , , . , , NSFastEnumerationState, , , .

​​ enumerateObjectsUsingBlock:.

, , , , , : , , .

0

Source: https://habr.com/ru/post/1532464/


All Articles