Нужно сделать снимок экрана без промедления

Итак, ребята, я использую эту функцию, чтобы сфотографировать UIWebView, который загружает электронную книгу, и отображать ее, пока пользователь отображает страницы.

-(UIImage*)captureScreen:(UIView*) viewToCapture
{

    UIGraphicsBeginImageContextWithOptions(viewToCapture.bounds.size, viewToCapture.opaque, 0.0);
    [viewToCapture.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return viewImage;
}

но проблема заключается в задержке (0,5 секунды) для получения изображения ... когда я тестирую профилировщик времени, инструменты указывают на эту строку [viewToCapture.layer renderInContext:UIGraphicsGetCurrentContext()]; как на ту, которая вызывает задержку ... так что любой совет, предложение, как я мог прийти над этой задержкой.

Заранее спасибо.

Примечания: 1. Я использую UIPageController для эффекта книги.

2. чтобы проверить, что я пробовал, перейдите по этой ссылке


person Malek_Jundi    schedule 03.05.2012    source источник


Ответы (2)


Лучший способ решить эту проблему — использовать делегатов. Это означает, что если вы скажете методу делегата создать изображение, он может сделать это в фоновом режиме и сказать вашему представлению: «Эй, теперь у меня есть изображение для XXX» (в зависимости от того, как вы его реализуете. Таким образом, вы можете загрузить свой просмотра с электронными книгами и просто показываете загрузчик в середине книги с фоном по умолчанию. Когда изображение готово, вы обновляете представление для книги с правильным изображением и удаляете загрузчик. Очень похоже на то, как Apple iBooks и любое другое хорошее приложение.

Пример из одного из моих собственных проектов (адаптированный к вашим потребностям, но для использования в UITableViewController):
BookDelegate.h

#import <Foundation/Foundation.h>

@class Book;

@protocol BookDelegate <NSObject>

@optional
- (void)didRecieveImageForBook:(NSString*)imagePath indexPath:(NSIndexPath*)indexPath;

@end

Book.h

#import <Foundation/Foundation.h>
#import "BookDelegate.h"

@interface Book : NSOperation <NSObject>
{   
    id <BookDelegate> delegate;
    SEL didRecieveImageForBookSelector;
}

@property (strong, nonatomic) id delegate;
@property (assign) SEL didRecieveImageForBookSelector;

- (NSString*)getBookImageForBookId:(int)BookId externalRefference:(NSString*)url indexPath:(NSIndexPath*)indexPath;
- (id)delegate;

// Delegate methods
- (void)didRecieveImageForBook:(NSString*)imagePath indexPath:(NSIndexPath*)indexPath;

@end

Book.m

#import "Book.h"
#import <objc/runtime.h>

@implementation Book

static char kAssociationKey;

@synthesize didRecieveImageForBookSelector;
@synthesize delegate;

- (id)init
{
    if (self = [super init])
    {
        [self setDidRecieveImageForBookSelector:@selector(didRecieveImageForBook:indexPath:)];
    }
    return self;
}

#pragma mark -
#pragma mark The default delegate functions

- (void)didRecieveImageForBook:(NSString*)imagePath indexPath:(NSIndexPath*)indexPath
{
    NSLog(@"********************************************************");
    NSLog(@"*** PLEASE IMPLEMENT THE FOLLOWING DELEGATE FUNCTION ***");
    NSLog(@"***       didRecieveImageForBook:indexPath:       ***");
    NSLog(@"********************************************************");
}

#pragma mark -
#pragma mark Function for fechting images

// This method is not adapted to what YOU need, but left my code here in case it might help you out.
- (NSString*)getBookImageForBookId:(int)bookId externalRefference:(NSString*)url indexPath:(NSIndexPath*)indexPath
{    
    NSString *ext = [[url lastPathComponent] pathExtension];

    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

    NSString *imagePath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%d.%@", APP_BookIMAGEPEFIX, BookId, ext]];
    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:imagePath];

    if (fileExists)
    {
        return imagePath;
    }
    else {
        NSURL *theUrl = [NSURL URLWithString:url];

        ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:theUrl];
        [request setDidFinishSelector:@selector(BookImageFetched:)];
        [request setDidFailSelector:@selector(processFailed:)];
        [request setTimeOutSeconds:60];
        [request setDownloadDestinationPath:imagePath];
        [request setDelegate:self];

        [request startAsynchronous];

        objc_setAssociatedObject(request, &kAssociationKey, indexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

        return @"";
    }
}

- (void)BookImageFetched:(ASIHTTPRequest *)request 
{
    NSIndexPath *indexPath = objc_getAssociatedObject(request, &kAssociationKey);
    NSString *imagePath = request.downloadDestinationPath;

    [[self delegate] performSelector:self.didRecieveImageForBookSelector withObject:imagePath withObject:indexPath];
}

#pragma mark -
#pragma mark delegate functions

- (id)delegate
{
        return delegate;
}

- (void)setDelegate:(id)newDelegate
{
        delegate = newDelegate;
}

#pragma mark -

@end
person Paul Peelen    schedule 03.05.2012
comment
то есть, другими словами, вы предлагаете захватить все страницы книги в виде изображений и сохранить в памяти?! - person Malek_Jundi; 03.05.2012
comment
Это один из способов сделать это. В одном из своих проектов я загрузил PNG-изображения для телеканалов, которые сохранил локально. Я проверил, было ли локальное изображение, и если оно было, я вернул его напрямую, в противном случае я вернул пустую строку и позволил методу делегата сообщить моему UITableView, что есть новое доступное изображение и что оно принадлежит определенному rowAtIndexPath. Затем я просто обновил эту ячейку новым изображением. - person Paul Peelen; 03.05.2012
comment
хорошо, я понимаю.. но в моем случае я загружаю главу (html-файл) и разбиваю ее на страницы с помощью функции js, поэтому у меня уже есть контент.. что мне нужно для захвата следующей/предыдущей страницы в тот момент, когда пользователь визуализировать страницу .. моя функция работает хорошо, но я ненавижу эту задержку, ваше решение вообще не решит задержку - person Malek_Jundi; 03.05.2012
comment
Нет, но это сделает задержку удобной для пользователя. Поскольку ваше приложение не блокируется, ваш пользователь может делать все, что захочет, например. покиньте эту страницу и никогда не смотрите на следующую или предыдущую страницу, поэтому задержка больше не должна быть такой важной. Правильно? Кроме того, если вы ранее визуализировали HTML и сохранили изображение в файл, мое решение быстро извлечет его и покажет, вместо повторного рендеринга... таким образом, без задержки. (однако этот код не включен в мой ответ, только идея, как это сделать). - person Paul Peelen; 03.05.2012
comment
это верно .. но страницы не статичны .. пользователь может изменить размер шрифта, тип .. добавить заметку, выделить или добавить закладку, для всего этого потребуются новые изображения .. поэтому лучше сразу сделать снимок экрана, а не извлекать его раньше , разве вы не знаете более быстрый способ захвата экрана, чем функция, которую я использовал? - person Malek_Jundi; 03.05.2012
comment
К сожалению нет. Я все еще не вижу проблемы. Когда вы меняете содержимое, покажите загрузчик на время ожидания пользователя, обновите изображение и скройте загрузчик. Пока пользователь понимает, что его/ее действие требует процесса для завершения, он/она это поймет. В качестве загрузчика вы могли бы использовать MBProgressHUD. - person Paul Peelen; 03.05.2012
comment
Однако, если это ваши требования, иметь ответ ‹ 0,5 секунды, то кто я такой, чтобы сомневаться в этом? Однако я сомневаюсь, что вы найдете 0.0, я предполагаю, что у вас всегда будет задержка, поэтому у вас должен быть пользовательский интерфейс, который информирует пользователя о задержке, поэтому он должен быть асинхронный, поэтому вы должны использовать, например. делегаты. - person Paul Peelen; 03.05.2012

Вы можете использовать GCD - я заметил, что в GCD в приведенной вами ссылке отсутствует шаг. Это то, что я использую для асинхронного получения изображения и уведомления, когда оно готово и работает нормально:

dispatch_queue_t concurrent = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    dispatch_async(concurrent, ^{
        __block UIImage *image = nil;
        dispatch_sync(concurrent, ^{
            //put code to grab image here
        });
        dispatch_sync(dispatch_get_main_queue(), ^{
            //this gets called when the above is finshed
            //you should also check if the image is nil or not
        });
    }); 

Надеюсь, поможет

для записи - я использую это для создания снимков UIView и всегда стараюсь поместить свою цель в родительское представление, даже если это временно - кажется, это ускоряет ее.

UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;

не уверен, помогает ли это или вы используете тот же подход. Я надеюсь, что вы скоро решите это :)

person fatuous.logic    schedule 03.05.2012
comment
к сожалению, это не устраняет задержку, отображаются белые страницы (без изображений)! - person Malek_Jundi; 03.05.2012
comment
ааа, так вы хотите... мгновенное мгновенное получение изображения... в зависимости от того, какое устройство вы используете и насколько сложно изображение, это может занять полсекунды. То, что я разместил в GCD, предполагало, что вы не сразу показывали изображение, извините. - person fatuous.logic; 04.05.2012