views:

702

answers:

2

Hi.

I've been working with MonoTouch for 3 weeks now and everything was going great until I had to display PDFs in my app.

Using Apple's Quartz 2D Programming Guide I managed to display the PDF.

The problem is, that the app runs out of memory. I tried to use the Dispose() methods on the CGPDFDocument and CGPDFPage objects, but then I get this error:

Stacktrace:

  at (wrapper managed-to-native) MonoTouch.CoreGraphics.CGPDFPage.CGPDFPageRelease (intptr) <0xffffffff>
  at MonoTouch.CoreGraphics.CGPDFPage.Dispose (bool) <0x00044>
  at MonoTouch.CoreGraphics.CGPDFPage.Finalize () <0x0002b>
  at (wrapper runtime-invoke) object.runtime_invoke_virtual_void__this__ (object,intptr,intptr,intptr) <0x0007b>

Native stacktrace:

0   FlapMag1                            0x00037514 mono_handle_native_sigsegv + 412
1   FlapMag1                            0x0000c010 mono_sigsegv_signal_handler + 348
2   libSystem.B.dylib                   0x339927f3 _sigtramp + 34
3   libCGVolute.A.dylib                 0x31c83d88 CPModelRelease + 24
4   libCGVolute.A.dylib                 0x31c84ad4 model_release + 56
5   CoreGraphics                        0x3113ced8 pdf_page_finalize + 68
6   CoreFoundation                      0x3388fae9 _CFRelease + 168
7   CoreFoundation                      0x3388f9c7 CFRelease + 66
8   CoreGraphics                        0x3113ce90 CGPDFPageRelease + 20
9   FlapMag1                            0x00248cc0 wrapper_managed_to_native_MonoTouch_CoreGraphics_CGPDFPage_CGPDFPageRelease_intptr + 64
* Assertion: should not be reached at ../../../../mono/mini/mini-darwin.c:258

This slowly drives me mad, because I tried everything I could think of.

In Apple's example there is the CGPDFDocumentRelease and CGPDFPageRelease, but these are missing from MonoTouch. Therefore I thought MT manages these object automatically, but apparently it doesn't or it's buggy.

Even when I don't mess with the CGPDF object's Dispose(), the above error occurs, when I remove the view, that contains the PDF, from the superview.

Has someone been able to work with PDFs in MonoTouch?

Thanks in advance.

UPDATE:
I tested PDF drawing in Obj-C with the same PDFs and found out that when I don't call CGPDFDocumentRelease() the memory consumption has the same tendency to go rapidly up as in MonoTouch. By calling the CGPDFDocumentRelease() in Obj-C the memory consumption is normal.
Therefore I think that MonoTouch really doesn't free up the CGPDFDocument and CGPDFPage objects and when I try to free them manually or indirectly (by removing the views which contain them), I get the above error.

This sucks big time and it is a real possibility now, that I have to rewrite the code in Obj-C ... F$#k!!

ANOTHER UPDATE:
I'm still not able to decypher why I get the release related errors, but I made a MonoTouch and an XCode project, where both do essentially the same thing: draw PDFs.
I compared the memory usage of both in Activity Monitor and found out that while the MonoTouch app increases memory usage constantly, the XCode one doesn't. I even call the Dispose() on the CGPDFDocument object in MonoTouch and still the memory consumption increases.
Neither apps crash with the release related error, but it's really worrying that the mem usage is so drasticly larger in the MonoTouch app...

I figure that my problem lies somewhere else, but I got here because my main app crashed after mem consumption got too high and I can't seem to find a way to bring it down, because I get these annoying release errors.

AND ANOTHER UPDATE:
The code that draws the pdf in the view's Draw() method:

CGContext context = UIGraphics.GetCurrentContext();

context.SaveState();

CGPDFDocument pdfDoc = CGPDFDocument.FromUrl(_pdfFileUrl);
if(pdfDoc.Pages >= 1)
{
    CGPDFPage pdfPage = pdfDoc.GetPage(1);  

    context.ScaleCTM(SCALE.Width, SCALE.Height);
    // the PDFRectangle is the media box rect of the page, which is hardcoded
    // for now
    context.TranslateCTM(-this.PDFRectangle.X, -this.PDFRectangle.Height - this.PDFRectangle.Y);

    context.DrawPDFPage(pdfPage);
}

pdfDoc.Dispose();

context.RestoreState();
A: 

The above stack trace shows that the PDF release code was called from the finalizer thread, not directly from Dispose.

Would you be so kind to provide me with a test case that exhibits the problem? Once we have a test case, we should be able to give you a fix or a workaround in a couple of hours.

miguel.de.icaza
Thank you for your prompt answer.What my app basically does is create a view for every pdf, because each pdf contains one page. The user is able to view the separate pdfs as one continous pdf. We had to do it this way, because otherwise the app would have to download the whole pdf first.The release problem arises when I remove the unneeded views from the view container.I'll write the drawing method in the question. But basically it loads the pdf document, gets the page, draws the page and then disposes the document (as is written in Apple's example).
Alpár
Hi. I rewrote my pdf drawing view based on your example on git and narrowed my problem down to the Dispose() method of CGPDFDocument. Every time I call Dispose() on my view (which, too, implements the IDisposable interface) an therein the Dispose() of pdf document is called, the app crashes with this error: (...) at (wrapper managed-to-native) MonoTouch.CoreGraphics.CGPDFDocument.CGPDFDocumentRelease (intptr) <0xffffffff> at MonoTouch.CoreGraphics.CGPDFDocument.Dispose (bool) <0x00044> at MonoTouch.CoreGraphics.CGPDFDocument.Dispose () <0x00027> (...)
Alpár
Thanks for the feedback, we now have a fix, and it will ship in our next update.
miguel.de.icaza
+3  A: 

This was caused by a bug in the MonoTouch Alpha which will be fixed in version 1.9.3

Geoff Norton