сбой в симуляторе, но iphone, когда я использую dispatch_aplly

Когда я использую dispatch_apply, чтобы добавить некоторые данные в nscountset, я получаю сбой в симуляторе, но iphone. И получаю сообщение "-[__NSArrayI isEqual:]: сообщение отправлено на освобожденный экземпляр 0x60000024c5a0", я не могу найти, как это произошло.

CGSize thumbSize = CGSizeMake(200,200);   
NSCountedSet *cls2 = [NSCountedSet setWithCapacity:thumbSize.width * thumbSize.height];
dispatch_apply(thumbSize.width, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
    int x = (int)index;
    for (int y = 0; y < thumbSize.height; y++) {
        if(y<x){
            continue;
        }
        int offset = 4*(x*y);
        int red = data[offset];
        int green = data[offset+1];
        int blue = data[offset+2];
        int alpha = data[offset+3];
        NSArray *clr2 = @[@(red),@(green),@(blue),@(alpha)];
        [cls2 addObject:clr2];
    }

});

сбой в [cls2 addobject:clr2]; в журнале указано «-[__NSArrayI isEqual:]: сообщение отправлено на освобожденный экземпляр 0x60000024c5a0». И в моей функции есть весь код, я хочу получить максимальное количество цветов в изображении.

CGSize thumbSize = CGSizeMake(200, 200);

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(NULL, thumbSize.width, thumbSize.height, 8, thumbSize.width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGRect drawRect = CGRectMake(0, 0, thumbSize.width, thumbSize.height);

CGContextDrawImage(context, drawRect, self.CGImage);

CGColorSpaceRelease(colorSpace);
unsigned char *data = CGBitmapContextGetData(context);
if (data == NULL)
{
    return nil;
}
NSCountedSet *cls2 = [NSCountedSet setWithCapacity:thumbSize.width * thumbSize.height];
dispatch_apply(thumbSize.width, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
    int x = (int) index;
    for (int y = 0; y < thumbSize.height; y++)
    {

        if (y < x)
        {
            continue;
        }
        int offset = 4 * (x * y);
        int red = data[offset];
        int green = data[offset + 1];
        int blue = data[offset + 2];
        int alpha = data[offset + 3];
        NSArray *clr3 = @[@(red), @(green), @(blue), @(alpha)];
        [cls2 addObject:clr3];
    }

});

CGContextRelease(context);

NSEnumerator *enumerator = [cls2 objectEnumerator];
NSArray *curColor = nil;
NSArray *maxColor = nil;
NSUInteger maxCount = 0;
while ((curColor = [enumerator nextObject]) != nil)
{
    NSUInteger tmpCount = [cls2 countForObject:curColor];
    if (tmpCount < maxCount) {
        continue;
    }

    maxCount = tmpCount;
    maxColor = curColor;
}

NSLog(@"colors: RGB A %f %d %d  %d",[maxColor[0] floatValue],[maxColor[1] intValue],[maxColor[2] intValue],[maxColor[3] intValue]);

return [UIColor colorWithRed:([maxColor[0] intValue]/255.0f) green:([maxColor[1] intValue]/255.0f) blue:([maxColor[2] intValue]/255.0f) alpha:([maxColor[3] intValue]/255.0f)];

person H.WZ    schedule 09.05.2017    source источник


Ответы (1)


NSCountedSet не является потокобезопасным — ссылка. Попытка мутировать один из параллельных потоков даст непредсказуемые результаты, как вы уже обнаружили.

Либо используйте простой цикл for без dispatch_apply, который при необходимости отправляется в фоновом потоке для обработки ваших данных, либо защищайте свое обновление NSCountedSet, отправляя его в последовательную очередь отправки.

person Paulw11    schedule 09.05.2017
comment
Я хочу сократить время добавления объекта в NSCountedSet, если я использую последовательную очередь отправки. Как я могу сократить время. - person H.WZ; 09.05.2017
comment
О, я понимаю, что вы говорите. Я попробую. - person H.WZ; 09.05.2017
comment
На самом деле, если подумать об этом немного подробнее, поскольку порядок обновления подсчитанного набора не важен, вы можете даже отправить обновление асинхронно в очередь последовательной отправки, но тогда вам понадобится какой-то другой метод отслеживания, когда набор был полностью обновлен. - возможно, dispatch_group - person Paulw11; 09.05.2017