I'm developing a page view controller for showing PDF files and I want to start rendering a UIImage from a PDF page in a different thread and pass the rendered image to the main thread through notifications.
I started by creating a different method that renders my page in a UIImage and post a notification when the image is ready but at least for now I'm still doing it on the main thread.
- (void)generatePage:(int)pageNumber withSize:(CGSize)size {
UIImage *resultingImage;
CGFloat sizeRatio = size.width/size.height;
CGPDFDocumentRef pdfRef = [self PDFDocumentRef];
CGPDFPageRef myPageRef = CGPDFDocumentGetPage(pdfRef, pageNumber);
CGRect pageRect = CGPDFPageGetBoxRect(myPageRef, kCGPDFMediaBox);
CGFloat pdfHWRatio = pageRect.size.width/pageRect.size.height;
CGFloat pdfScale;
if (sizeRatio < pdfHWRatio) {
pdfScale = size.width/pageRect.size.width;
}
else {
pdfScale = size.height/pageRect.size.height;
}
pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
pageRect.origin = CGPointZero;
UIGraphicsBeginImageContext(pageRect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,pageRect);
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, pageRect.size.height);
CGContextScaleCTM(context, pdfScale, -pdfScale);
CGContextDrawPDFPage(context, myPageRef);
CGContextRestoreGState(context);
resultingImage = UIGraphicsGetImageFromCurrentImageContext();
if (resultingImage) {
[pagesCache setObject:resultingImage
forKey:[self generateCacheNameWithSize:size
andPageNumber:pageNumber]];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:
resultingImage,
[NSNumber numberWithInt:pageNumber],
nil]
forKeys:[NSArray arrayWithObjects:
CatalogRenderedPageImageKey,
CatalogRenderedPageNumberKey,
nil]];
NSNotification *note = [NSNotification notificationWithName:CatalogRenderPageNotification
object:self
userInfo:userInfo];
[[NSNotificationCenter defaultCenter] postNotification:note];
}
UIGraphicsEndImageContext();
CGPDFDocumentRelease(pdfRef);
}
I'm successfully getting the notification and the UIImage is correctly acquired (same object id) but the UIImageView is empty.
- (void) imageLoaded:(NSNotification *)note {
NSDictionary *userInfo = note.userInfo;
NSNumber *pageNumber = [userInfo objectForKey:CatalogRenderedPageNumberKey];
if ([self.pageNumber isEqualToNumber:pageNumber]) {
UIImage *image = [userInfo objectForKey:CatalogRenderedPageImageKey];
self.image = image;
self.imageView.image = _image;
[[NSNotificationCenter defaultCenter] removeObserver:self name:CatalogRenderPageNotification object:self.catalog];
}
}
What am I missing? I've checked the storage property in the UIImageView and it's being filled with the UIImage.
You may have noticed that I'm saving my rendered images in a cache and truth is that when I get the images from that cache I'm able to see them in the UIImageView so I dismiss the chance that the UIImage is being generated badly.
UPDATE: I started calling the generatePage in a different thread:
dispatch_async(dispatch_queue_create("renderingQueue", DISPATCH_QUEUE_CONCURRENT), ^{
[self generatePage:pageNumber withSize:size];
});
And posting the notification in the main thread as @phyx23 suggested. It now works but I still don't understand why it didn't work before.
I'm leaving it open so that anyone can leave their thoughts on why this would happen.