Ленивый рисунок изображения - PullRequest
5 голосов
/ 26 апреля 2011

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

Как это обычно достигается? Сохранить ссылку на графический контекст или представление, которое запрашивало чертеж, и отрисовать его там с задержкой, когда внутреннее представление объектов будет полностью отображено?

Или есть другие стандартные механизмы какао, чтобы справиться с этим (например, NSImage делает ленивое рисование при инициализации NSURL)?

Разъяснения:


  • Я на MacOS, а не на iOS
  • Использование некоторых NSView s -setNeedsDisplay: - это не тот ответ, который я ищу (NSImage не зависит от -setNeedsDisplay:)

Ответы [ 2 ]

1 голос
/ 26 апреля 2011

Вы должны использовать 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.
1 голос
/ 26 апреля 2011

Мне нравится класс EGOImageView для этих целей.Он действительно прост в использовании и включает в себя несколько приятных бонусов, например, механизм кэширования.

Подробнее об EGOImageView здесь (включая ссылку для скачивания с Github):

http://developers.enormego.com/view/what_if_images_on_the_iphone_were_as_easy_as_html

...