2009-07-23 4 views
0

Ich habe eine Test-iPhone-App gemacht, um zu versuchen zu verstehen, warum ich in einigen anderen Projekten Speicher lecke. Ich bin auch ein Neuling, wenn es um Obj-C/iPhone geht.RetainCount Frage mit verschachtelten UIViews in iPhone App

Im Grunde erzeugt der View-Controller 5 zufällig gefärbte Boxen, die selbst UIView-Unterklassen sind.

Doppelklick auf eines dieser Felder löst eine Benachrichtigung an den View-Controller aus. Der Controller geht dann durch und löscht die aktuellen 5 Boxen und erstellt 5 zufälligere an dieser Stelle. Doppelklick auf eine beliebige Option wird fortgesetzt.

Hier ist die Ausgabe der Konsole meines NSLogs, wenn ich das erste Feld doppelklicken, dann die vierte Box, dann ist die erste Box wieder:

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 
------------------------------------ 

Was ich versuche zu verstehen, warum die Zählungen behalten bevor ich die Boxen entferne ist 2. Und auch warum die Box, auf die ich klicke, inkrementell höher ist. Ich stelle fest, dass der Anstieg für den, den ich anklicke, wegen der Benachrichtigungskram ist, warum unterscheiden sie sich inkrementell?

Wird ein Zählerstand von 2 vor dem Entfernen bedeuten, dass ich diese Ansichten lecke.

einschließlich meines Codes für die Viewcontroller und die UIView Bluebox-Klasse.

Jede Hilfe sehr geschätzt. Ich habe versucht, das Leaks-Instrument darauf laufen zu lassen, aber es stürzt einfach mit EXC_BAD_ACCESS ab, so dass ich festhalte, herauszufinden, ob ich nur mit dem normalen Debugging arbeiten kann.

-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 Klasse

#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 

Antwort

0

Die 2 Zahl halten, ist höchstwahrscheinlich aus der NewView und boxView in Ihrer ersten Funktion. Da beide Variablen auf dieselbe Ansicht zugreifen, wird sie zweimal gespeichert (bei der Erstellung und beim Kopieren). Ich würde BoxView einfach von Anfang an verwenden und sehen, ob das irgendetwas betrifft.

Ich bin mir nicht sicher, was die 10, 13 und 10-Zählungen sind, da einige schnelle Voreinstellungen standardmäßig ausgeführt werden, wenn Sie auf etwas klicken.

Ich würde vorschlagen, Lecks, um mit Ihrem Problem zu helfen, aber ich denke, Sie können das nicht zum Laufen bekommen. Ich würde vorschlagen, Ihr Testprojekt von Grund auf neu zu erstellen, nur damit Sie diese Ressource haben können.

+0

entfernt die newview und geändert Allo zu: boxview = [[UIView Alloc] initWithFrame: CGRectMake (0,0,320,480)]; behalten zählt sind immer noch 2 –

+0

Wirklich, verdammt. Ich dachte, ich würde gerade anfangen zu verstehen, wie das Retain/Release-System funktioniert. Ich fürchte, ich kann nicht viel mehr Hilfe sein, aber ich bin mir sicher, dass die Apple Docs die Dinge ein wenig aufklären ... – TahoeWolverine

+0

Ich konnte das Instrument in Funktion bringen, indem ich das Projekt von Grund auf mit demselben Code neu erstellte. Es werden keine Lecks erkannt, und Net Bytes in ObjectAlloc scheint bei 273600 für All Allocations konstant zu bleiben. Bedeutet das, wie viel Speicher die App gerade nutzt, also kein Speicherleck? –

0

ändern

boxview = newview; 

zu

self.boxview = newview; 

Wenn Sie nicht boxview als Eigenschaft zugreifen kann, wird es nicht das Objekt behalten. Was passiert, ist, dass Sie newview freigeben, so dass retainCount gleich 0 ist, und somit die Zuweisung aufheben, so dass boxview jetzt auf einen schlechten Speicherort zeigt. Dies wird Ihre App mit einer EXC_BAD_ACCESS Ausnahme beenden.

Etwas, das mir mit EXC_BAD_ACCESS Ausnahmen geholfen hat, ist die ability to track an object's malloc history.

Sie wissen also, EXC_BAD_ACCESS bedeutet, dass Sie versucht haben, auf eine Instanz eines Objekts zuzugreifen, das nicht mehr existiert. In Ihrem Fall, wenn newview freigegeben und freigegeben wurde, wurde der Speicher wahrscheinlich durch ein anderes Objekt überschrieben, das dynamisch zugewiesen wurde.