Вы должны использовать NSOperation ;либо NSInvocationOperation
, если у вас есть конкретный объект, выполняющий рендеринг, либо NSBlockOperation
, если рендеринг достаточно прост, чтобы поместиться в одну функцию.
Если вы можете начать рендеринг до того, как вы действительно достигнете drawRect:
своего представления, то сделайте это (возможно, ваш делегат приложения запускает процесс прямо при запуске).В противном случае, проверьте в drawRect:
, доступен ли контент;если нет, начните операцию и продолжите работу с другим чертежом.Когда объект рендеринга завершит свою работу, он, вероятно, либо отправит уведомление, либо, если вы вернете ему ссылку на представление, вызовет setNeedsDisplay:
Вдоль строк вашего последнего предложения вы также можете рассмотретьВаш объект рендеринга может вернуть частично визуализированное изображение.Я не уверен в природе вашего рендеринга, но может быть возможно получить результаты в определенных точках (конец каждого n циклов или каждые n строк пикселей), поместив их в отдельный NSImage
изтот же размер, что и конечное изображение (при необходимости добавление в конце), и сделать это частичное изображение доступным для просмотра для рисования.
ОБНОВЛЕНИЕ: NSImage
не "полагается" на setNeedsDisplay:
илиимея ссылку на представление, потому что она не представляет часть экрана.Все, что он делает, это содержит данные для изображения;он может нарисовать только внутри вида, который затем «отображается» - фактически нарисован на экране.Когда вы используете initByReferencingURL:
, он сохраняет URL-адрес, а затем, когда другой объект (например, представление, которое содержит изображение и должно отображаться), запрашивает его содержимое, он делает то, что сделал бы, если бы вы использовали initWithURL:
, который открывает файл и считывает его содержимое в память.Это не рисовать все же лениво; только рисует в представление, которое ему нужно, , когда это представление рисует.
Подклассы NSImage
для реализации собственной отложенной загрузки или отложенного рендеринга могут нелегко;он использует вспомогательные классы, которые, как я считаю, являются частью кластера классов , поэтому я предлагаю иметь объект «рендер», который содержит и возвращает NSImage
.
MORE:
Пользовательское представление drawRect
:
- (void)drawRect:(NSRect)dirtyRect {
NSLog(@"Entered: %@", NSStringFromSelector(_cmd));
// Use a nice big image of the Milky Way -- this is about 5MB
NSImage * lazyImage = [[[NSImage alloc] initByReferencingURL:
[NSURL URLWithString:@"http://www.eso.org/public/archives/images/original/milkyway.jpg"]]
autorelease];
NSLog(@"Image instantiated.");
[lazyImage drawInRect:[self bounds] fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
NSLog(@"Image drawn"); // 2 minutes later; sometimes 3 in my testing
[[NSColor yellowColor] set];
[[NSBezierPath bezierPathWithRect:NSInsetRect([self bounds], 4, 4)] stroke];
NSLog(@"Bezier path drawn; exiting drawRect.");
}
Вывод журнала из этого;обратите внимание, что создание экземпляров происходит очень быстро, но загрузка и отрисовка занимает две минуты, в течение которых ничего не рисуется, а приложение больше ничего не делает (вращающийся пляжный мяч):
2011-04-27 21:33:00.899 SetNeedsDisplay[80162:a0b] Entered: drawRect:
2011-04-27 21:33:00.901 SetNeedsDisplay[80162:a0b] Image instantiated.
2011-04-27 21:34:57.911 SetNeedsDisplay[80162:a0b] Image drawn.
2011-04-27 21:34:57.912 SetNeedsDisplay[80162:a0b] Bezier path drawn; exiting drawRect.