I am writing a program which redraws a graph every so often. Unfortunately it seems that for some reason core graphics does not seem to release the previous graphic so I run into memory problems fast. How can I force it to release memory at the end of each draw?
Not that this is not a memory leak as the memory does get released when I leave close that view. I have tried moving the NSTimer to several places in the code to no avail.
Here is the code below with the files going from most important to (potentially) irrelevant.
First is the core file+header which draws the graphic (in this case a sine wave) every so often.
GraphicsView.h
#import <UIKit/UIKit.h>
#import "Model.h"
@interface GraphicsView : UIView
{
Model * model;
}
@end
GraphicsView.m
#import "GraphicsView.h"
@implementation GraphicsView
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
model=[Model sharedModel];
[NSTimer scheduledTimerWithTimeInterval:.010 target:self selector:@selector(setNeedsDisplay) userInfo:nil repeats:YES];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
int now=[model n];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height));
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextMoveToPoint(context, 0.0, 0.0);
double xc_old=0;
double yc_old=100;
for (int i=0;i<now;i++)
{
double xc=(double)i/(double)now*200;
double yc=100-100*sin((double)i/6);
CGContextMoveToPoint(context, xc_old, yc_old);
CGContextAddLineToPoint(context, xc, yc);
CGContextStrokePath(context);
xc_old=xc;
yc_old=yc;
}
}
- (void)dealloc {
[super dealloc];
}
@end
The view controller header:
#import <UIKit/UIKit.h>
#import "GraphicsView.h"
@interface SbarLeakAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
Model *model;
GraphicsView * gv;
NSTimer * timer;
}
@end
The view controller itself.
#import "SbarLeakAppDelegate.h"
@implementation SbarLeakAppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
model=[Model sharedModel];
CGRect appRect;
CGRect frame = CGRectInset(appRect, 0.0f, 0.0f);
appRect.origin=CGPointMake(0.0, 40.0);
appRect.size = CGSizeMake(200.0f, 200.0f);
frame = CGRectInset(appRect, 0.0f, 0.0f);
gv=[[GraphicsView alloc] initWithFrame:appRect];
[gv setFrame:frame];
[window addSubview:gv];
[gv release];
[window makeKeyAndVisible];
}
-(void) viewDidAppear:(id)sender
{
//timer=[NSTimer scheduledTimerWithTimeInterval:.250 target:gv selector:@selector(setNeedsDisplay) userInfo:nil repeats:YES];
}
- (void)dealloc
{
[window release];
[super dealloc];
}
@end
This code is only included for completeness but (should not) affect the question. The data source header file (just a simple integer)
#import <UIKit/UIKit.h>
@interface Model : NSObject
{
int n;
}
@property int n;
+(Model *) sharedModel;
-(void) inc;
@end
The data source, Model.m:
#import "Model.h"
@implementation Model
static Model * sharedModel = nil;
+ (Model *) sharedModel
{
if (sharedModel == nil)
sharedModel = [[self alloc] init];
return sharedModel;
}
@synthesize n;
-(id) init
{
self=[super init];
[NSTimer scheduledTimerWithTimeInterval:.05 target:self selector:@selector(inc) userInfo:nil repeats:YES];
return self;
}
-(void) inc
{
n++;
}
@end