Использование NSOperation странно медленно - PullRequest
3 голосов
/ 01 февраля 2011

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

Я отображаю вид с пустыми рамками миниатюр и соответствующим индикатором активности, чтобы сказать пользователю «держись, они в пути». Но это занимает так много времени, что я подумываю над тем, чтобы поставить музыку для лифта, чтобы сделать ожидание более приятным.

У меня установлено значение NSOperationQueue с 10 одновременными операциями. Установка, которая немного помогла с загрузочной частью, но совсем немного. Загрузка одного большого пальца все еще занимает около 6 секунд, и это странная вещь: загрузка 10 занимает то же самое. Следующий код является самой операцией

@class ThumbnailView;

@protocol LoadThumbnailOperationDelegate;
@interface LoadThumbnailOperation : NSOperation {
    NSString *key;
    id<LoadThumbnailOperationDelegate> delegate;
    @private
    CGSize _size;
    CGPDFDocumentRef _docRef;
    UIImage * _image;
    NSInteger _page;


}
@property (nonatomic,retain) NSString * key;
@property (nonatomic,assign) id<LoadThumbnailOperationDelegate>delegate;
-(id)initWithPage:(NSInteger)page  operationKey:(NSString *)opKey fromDocRef:(CGPDFDocumentRef)docRef size:(CGSize)size delegate:(id<LoadThumbnailOperationDelegate>)aDelegate;
-(NSInteger)getPage ;
@protocol LoadThumbnailOperationDelegate <NSObject>

-(void)operation:(LoadThumbnailOperation*)operation finishedLoadingThumbnail:(UIImage*)image;
@end


@interface LoadThumbnailOperation (private)
-(UIImage*)makeThumbnailForPage:(NSInteger)page;

@end

@implementation LoadThumbnailOperation
@synthesize key;
@synthesize delegate;

-(id)initWithPage:(NSInteger)page  operationKey:(NSString *)opKey fromDocRef:(CGPDFDocumentRef)docRef size:(CGSize)size delegate:(id<LoadThumbnailOperationDelegate>)aDelegate{

    self = [super init];
    if (self) {

        self.key = opKey;
        _docRef = docRef;
        CGPDFDocumentRetain(_docRef);
        _size = size;
        _page = page;
        self.delegate = delegate;

    }
    return self;
}

-(void)main {
#if DEBUG
    NSLog( @"LoadThumbnailOperaiton.m -> main key:%@",key);
#endif
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    if (![self isCancelled]) {
        _image = [self makeThumbnailForPage:_page];
        [_image retain];
    }
    if(![self isCancelled]){
        if ([delegate respondsToSelector:@selector(operation:finishedLoadingThumbnail:)]) {
            [delegate operation:self finishedLoadingThumbnail:_image];
        }
    }

    [pool release];
}


-(void)dealloc {


    [key release];
    CGPDFDocumentRelease(_docRef);
    [_image release];
    [super dealloc];

}
#pragma mark - 
#pragma mark graphics 


-(UIImage*) makeThumbnailForPage :(NSInteger) page  {
#if DEBUG
    NSLog( @"LoadThumbnailOperaiton.m -> makeThumbnailForPage:%d",page);
#endif
    CGPDFPageRef pdfPage = CGPDFDocumentGetPage(_docRef, page);
    if (pdfPage !=NULL){
        CGPDFPageRetain(pdfPage);

    }else {
        NSAssert (pdfPage==NULL,@"pdf page NULL");
    }

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, 
                                                 _size.width, 
                                                 _size.height, 
                                                 8,                      /* bits per component*/
                                                 _size.width * 4,   /* bytes per row */
                                                 colorSpace, 
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextClipToRect(context, CGRectMake(0, 0, _size.width,_size.height));


    CGRect pdfPageRect = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
    CGRect contextRect = CGContextGetClipBoundingBox(context);
    CGAffineTransform transform =aspectFit(pdfPageRect, contextRect);

    CGContextConcatCTM(context, transform);
    CGContextDrawPDFPage(context, pdfPage);

    /* 
     create bitmap context
     */
    CGImageRef image = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
    UIImage *uiImage = [[UIImage alloc]initWithCGImage:image];

    // clean up
    [uiImage autorelease];
    CGImageRelease(image);
    CGPDFPageRelease(pdfPage);
    return uiImage;
}

-(NSInteger)getPage {

    return _page;
}
@end

Это метод делегата на контроллере представления, который добавляет загруженные изображения

ПРИМЕЧАНИЕ: это приложение только для iPad

Заранее благодарю за помощь

Ответы [ 2 ]

3 голосов
/ 07 марта 2011

Ну, Я нашел решение этой проблемы. Я решил это, проверив, был ли сделан вызов делегата в главном потоке или нет. По-видимому, операции выполнялись довольно быстро, но вызов делегата был не из-за того, что он не был выполнен в основном потоке. Поэтому убедитесь, что вы выполняете вызов делегата в этом потоке, используя метод - [NSObject executeSelectorOnMainThread:].

Это все еще может не быть быстрым для некоторых клиентов. В итоге я сгенерировал миниатюры pdf с помощью automator, добавил их в комплект приложений и вместо этого загрузил их с диска. Это гораздо быстрее, чем генерировать их на Ipad.

1 голос
/ 01 февраля 2011

ПРИМЕЧАНИЕ: это приложение предназначено только для iPad

iPad имеет одно ядро.

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

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

...