I've made a test iPhone app to try and understand why I may be leaking memory in some other projects. I'm also a newbie when it comes to Obj-C/iPhone.
Basically the view controller creates 5 randomly colored boxes which are themselves sub-classed UIViews.
double-Clicking on any of these boxes fires off a notification to the view controller. The controller then goes through and deletes the current 5 boxes, and creates 5 more random one in there place. double-Clicking any again continues on the same.
Here's the console output of my NSLogs when i double-click the 1st box, then the 4th box, then the 1st box again:
Deleting boxes in Box View
------------------------------------
Deleting boxes in Box View
Box view retain count before Remove: 10
Box view retain count before Remove: 2
Box view retain count before Remove: 2
Box view retain count before Remove: 2
Box view retain count before Remove: 2
------------------------------------
Deleting boxes in Box View
Box view retain count before Remove: 2
Box view retain count before Remove: 2
Box view retain count before Remove: 2
Box view retain count before Remove: 13
Box view retain count before Remove: 2
------------------------------------
Deleting boxes in Box View
Box view retain count before Remove: 10
Box view retain count before Remove: 2
Box view retain count before Remove: 2
Box view retain count before Remove: 2
Box view retain count before Remove: 2
------------------------------------
What i'm trying to understand is why the retain counts before I remove the boxes is 2. And also why the box I click on is incrementally higher. I figure the the increase for the one i click is because of the notification stuff, by why are they incrementally different?
Will a retain count of 2 before the remove mean that i'm leaking these views.
including my code for both the viewcontroller and the UIView bluebox class.
Any help greatly appreciated. I've tried running the Leaks instrument on it but it just crashes with EXC_BAD_ACCESS, so i'm stuck trying to figure out with just regular debug.
Controller
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>;
@interface BoxViewController : UIViewController
{
UIView *boxview;
}
@property (nonatomic, retain) UIView *boxview;
-(void)cleanUp;
-(void)doTestLayout;
@end
#import "BoxViewController.h"
#import "BlueBox.h"
#import <Foundation/NSNotification.h>
@implementation BoxViewController
@synthesize boxview;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
UIView* newview = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,480)];
newview.backgroundColor = [UIColor clearColor];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nodeupEventReceived:) name:@"nodeClicked" object:nil];
boxview = newview;
[self.view addSubview:boxview];
[self doTestLayout];
[super viewDidLoad];
[newview release];
}
-(void)doTestLayout
{
[self cleanUp];
int x_offset = 10;
BlueBox *bb;
for(int i=0; i < 5; i++)
{
bb = [[BlueBox alloc] init];
CGRect cFrame = CGRectMake(x_offset,100, 30, 30);
bb.frame = cFrame;
//NSLog(@"Placing Box#%i",i);
//NSLog (@"Box retain count: %d", [bb retainCount]);
[boxview addSubview:bb];
//NSLog (@"Box view retain count after adding to view: %d", [bb retainCount]);
x_offset += 40;
[bb release];
//NSLog (@"Boxview retain count after release: %d", [bb retainCount]);
}
}
-(void) cleanUp
{
NSLog(@"Deleting boxes in Box View");
if(boxview)
{
for (UIView *view in boxview.subviews) {
NSLog (@"Box view retain count before Remove: %d", [view retainCount]);
[view removeFromSuperview];
}
}
NSLog(@"------------------------------------");
}
-(void) nodeupEventReceived:(id)sender
{
//NSLog(@"Event received - Relayout");
[self doTestLayout];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[boxview release];
[super dealloc];
}
@end
UIView class
#import <UIKit/UIKit.h>
@interface BlueBox : UIView {
}
@end
#import "BlueBox.h"
@implementation BlueBox
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, .48, .53, .67, 1.0);
CGFloat red = (CGFloat)random()/(CGFloat)RAND_MAX;
CGFloat green = (CGFloat)random()/(CGFloat)RAND_MAX;
CGFloat blue = (CGFloat)random()/(CGFloat)RAND_MAX;
CGContextSetRGBFillColor(context, red, green,blue, 1.0);
CGContextSetLineWidth(context, 2.0);
CGRect rrect = CGRectMake(0,0, 30, 30);
CGFloat radius = 5.0;
CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect);
CGContextMoveToPoint(context, minx, midy);
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
CGContextClosePath(context);
// Fill & stroke the path
CGContextDrawPath(context, kCGPathFillStroke);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
//NSLog(@"Touched");
//Number of touches on the screen
NSSet *allTouches = [event allTouches];
switch ([allTouches count])
{
case 1:
{
//Get the first touch.
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
switch([touch tapCount])
{
case 1://Single tap
//NSLog(@"Single touch");
break;
case 2://Double tap.
{
//NSLog(@"Double touch.");
[[NSNotificationCenter defaultCenter] postNotificationName:@"nodeClicked" object:self];
break;
}
}
}
break;
}
}
- (void)dealloc {
[super dealloc];
}
@end