I have failed in solving this problem during the week-end... I thought to have a good knowledge in Objective-C memory management but this one is very hard to solve.
To sum-up context : I have a suclassed UIViewController that I push in my navigationcontroller. This UIViewController contains a UIScrollView (created in IB). In the UIViewController viewDidLoad() function, I add a background PDF (in a CATiledLayer sublayer of an UIview layer).
The problem is that when I pop the UIViewController from the navigation controller, the app crashes.
Using Zombies instruments and NSZombieLevel shows that it is because the UIViewController is over-released.
Here is the UIViewController :
@interface PlanViewController : UIViewController <UIScrollViewDelegate> {
UIScrollView *panelScrollView;
UIView *myContentView;
CGPDFDocumentRef myDocumentRef;
CGPDFPageRef myPageRef;
}
@property (nonatomic, retain) IBOutlet UIScrollView *panelScrollView;
@property (nonatomic, retain) UIView *myContentView;
@end
@implementation PlanViewController
@synthesize panelScrollView;
@synthesize myContentView;
- (void)viewDidLoad {
[self setTitle:@"Plan"];
myDocumentRef = CGPDFDocumentCreateWithURL((CFURLRef)[[NSBundle mainBundle] URLForResource:@"salonMap" withExtension:@"pdf"]);
myPageRef = CGPDFDocumentGetPage(myDocumentRef, 1);
CGRect pageRect = CGRectIntegral(CGPDFPageGetBoxRect(myPageRef, kCGPDFCropBox));
CATiledLayer *tiledLayer = [[CATiledLayer alloc] init];
[tiledLayer setDelegate:self];
[tiledLayer setTileSize:CGSizeMake(1024.0, 1024.0)];
[tiledLayer setLevelsOfDetail:4];
[tiledLayer setLevelsOfDetailBias:8];
[tiledLayer setFrame:pageRect];
UIView *newView = [[UIView alloc] initWithFrame:pageRect];
[newView.layer addSublayer:tiledLayer];
[newView setTag:555];
[self setMyContentView:newView];
[newView release];
[tiledLayer release];
[panelScrollView setDelegate:self];
[panelScrollView setContentSize:pageRect.size];
[panelScrollView setMaximumZoomScale:5];
[panelScrollView addSubview:myContentView];
[panelScrollView setClipsToBounds: YES];
[panelScrollView setMaximumZoomScale:20.0];
[panelScrollView setMinimumZoomScale:1.0];
[panelScrollView setZoomScale:1];
[self initPinsOnMap];
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(ctx, CGContextGetClipBoundingBox(ctx));
CGContextTranslateCTM(ctx, 0.0, layer.bounds.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextConcatCTM(ctx, CGPDFPageGetDrawingTransform(myPageRef, kCGPDFCropBox, layer.bounds, 0, true));
CGContextDrawPDFPage(ctx, myPageRef);
}
- (void)dealloc {
[panelScrollView release];
[myContentView release];
CGPDFDocumentRelease(myDocumentRef), myDocumentRef = NULL;
myPageRef = NULL;
[super dealloc];
}
@end
After having played with // during hours, I discovered that the over released issue only occurs if I "[newView.layer addSublayer:tiledLayer];". If there is no subLayer added, the UIViewController is not overreleased.
I push my ViewController like this :
PlanViewController *trailsController = [[PlanViewController alloc] initWithNibName:@"PlanView" bundle:nil ];
[self.navigationController pushViewController:trailsController animated:YES];
[trailsController release];
I am wondering what I am doing wrong. I am sure to respect Memory Management guide. I think the issue comes from CALayer. I tried with and without using a pdf in the CALayer but it changes nothing...
But no matter how I code it, it always lead to a : ** -[PlanViewController isKindOfClass:]: message sent to deallocated instance 0xc641750**
Instruments Zombies show me an overrelease on :
88 PlanViewController Zombie -1 6909541120 0x64a6a00 0 UIKit -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]
Do you have an hint ?
Thanks a lot for your help
SOLVED !!! Maybe it could help :
In fact, asynchronous redraws are called by CATiledLayer. When releasing UIViewController you have to say to CATiledLayer that its delegate is not anymore alive. I added a reference (assign) to my CATiledLayer and in my dealloc function i do :
self.PDFTiledLayer.contents=nil;
self.PDFTiledLayer.delegate=nil;
[self.PDFTiledLayer removeFromSuperlayer];
I hope you won't lose as many time I lost...