2013-11-13 1 views
4

В моем коде я подклассифицировал NSView и в своем методе drawRect, я создаю три потока для выполнения чертежа.Несколько потоков для рисования в NSView

-(void)drawRect:(NSRect)dirtyRect 
{ 
    [[self window] setAllowsConcurrentViewDrawing:YES]; 
    [self setCanDrawConcurrently:YES]; 

    [NSThread detachNewThreadSelector:@selector(DrawText) toTarget:self withObject:nil]; 
    [NSThread detachNewThreadSelector:@selector(DrawRectangle) toTarget:self withObject:nil]; 
    [NSThread detachNewThreadSelector:@selector(DrawGradient) toTarget:self withObject:nil]; 

    //Wherease these functions DrawText, DrawRectangle and DrawGradient performs their task as suggested by name. 

    //In DrawText, DrawRectangle, and DrawGradient lockFocus and unlockFocus is being 
    // used for multithreaded drawing. 

} 

Когда я запускаю ту же программу из Xcode, она работает нормально. Результат показан ниже. Single threaded

Но когда я запускаю его снаружи, возникает проблема, и результат показан ниже. Multithreaded

Во-первых, я хотел бы знать, правильно ли это сделать из вторичной резьбы? Или что еще можно сделать из вторичной нити?

В чем причина этой проблемы?

ответ

0

Я читал около NSGraphicsContext Restriction по адресу Thread guide.

Здесь я нашел следующую строку:

Если вы делаете любой рисунок из вторичного потока, вы должны потопить ваш рисунок требует вручную. Cocoa автоматически не обновляет представления с содержанием, полученным из вторичных потоков, поэтому вам нужно вызвать метод flushGraphics для NSGraphicsContext, когда вы закончите рисовать. Если ваше приложение использует контент только из основного потока, вам не нужно скрывать ваши призывы к рисованию.

После звонка flushGraphics, он отлично работает.

1

Вы должны только рисовать на экране из основного потока.

Редактировать: Это, по-видимому, очень сложно, поэтому вам лучше рисовать на экране из основного потока. ;)

Если вам нужно сделать что-то, что занимает слишком много времени, чтобы избежать блокировки основного потока, рассмотрите возможность использования потока для рисования в контексте вне экрана, а затем скопируйте этот контекст на экран основного потока.

5

Ken Aspeslagh немного неверен в отношении рисования вторичных потоков (он прав, как правило, это плохая идея). Из того, что я вижу в вашем коде, у вас нет хорошего варианта для рисования на вторичном потоке. Можете ли вы объяснить, почему вы хотите это сделать?

Вы сами уже обнаружили setCanDrawConcurrently:, в котором явно говорится о вызове drawRect: из фонового потока. Обратите внимание, что для окна просмотра должно быть установлено значение allowsConcurrentViewDrawing для YES (это значение по умолчанию).

Apples own Cocoa Drawing Guide имеет раздел на чертеже из вторичных резьб. Я выделил некоторые части, которые, я думаю, имеют отношение к вам.

В комплекте приложений для каждого окна и комбинации потоков используется уникальный графический контекст. Поскольку каждый поток имеет свой собственный объект контекста графики для данного окна, можно использовать вторичные потоки для рисования в этом окне. Однако есть некоторые оговорки.

Во время обычного цикла обновления для окон все запросы на рисование отправляются в основной поток приложения для обработки. Обычный цикл обновления происходит, когда пользовательское событие вызывает изменение в вашем пользовательском интерфейсе. В этой ситуации вы вызываете метод setNeedsDisplay: или setNeedsDisplayInRect: (или семейство методов отображения) из основного потока приложения, чтобы аннулировать части вашего представления, которые требуют перерисовки. Вы не должны вызывать эти методы из любых вторичных потоков.

Если вы хотите обновить окно или просмотр из вторичного потока, вы должны вручную заблокировать фокус на окне или просмотреть и инициировать рисование самостоятельно. Фокусировка блокировки настраивает среду рисования для графического контекста этого окна. После блокировки вы можете настроить среду рисования, выдать команды рисования как обычно, а затем очистить содержимое графического контекста до буфера окна.

Для того, чтобы делать рисунки регулярно на дополнительной резьбе, вы должны уведомить об этом себя.. Самый простой способ отправки регулярных уведомлений - использовать объект NSTimer или NSAnimation. Для получения дополнительной информации о том, как оживить содержание в разделе «Методы Advanced черчения.»

The Cocoa Threading Programming Guide также говорит, что это:

Если вы хотите использовать нить, чтобы привлечь к виду, скобка все рисование код между методами lockFocusIfCanDraw и unlockFocus из NSView

Просто в стороне, НОД блок вызов, вероятно, гораздо лучше, способ для выполнения небольших наборов операций в фоновом режиме, чем NSThread.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
    // you can put each of these calls in their own queue if you want 
    [self DrawText]; 
    [self DrawRectangle]; 
    [self DrawGradient]; 
}); 

Однако, это, вероятно, не имеет ничего общего с вашей проблемой; Я упоминаю об этом только потому, что думаю, что вам будет лучше использовать очереди GCD.

+0

Интересно! Благодаря! –

+2

Важное примечание: установка 'canDrawConcurrently' на' YES' означает, что ** 'drawRect:' сам будет вызываться в фоновом потоке. ** Вам не нужно и не следует, а затем вызывать несколько других методов рисования в других потоках а затем вернуться. –

+0

@PeterHosey ты уверен? docs говорят, что «можно вызвать в фоновом потоке», а не «будет» –

 Смежные вопросы

  • Нет связанных вопросов^_^