Skip to main content

Memory Leak & App Crash when going back to Album List



I'm using three20 to create image viewer. First i'm creating list of albums from the sql db and when user selects any album, its url string is passed to the this code that creates thums of available pics on network using XML Parser. everything works fine but when user goes back to the album list and selects another album. app crashes with 'Thread 1: Program received singal: "EXC+BAD_ACCESS" in main.m . plus XCode Product Analyze gives potential memory leak where i'm creating photoSource in the viewDidLoad. Here is the code







#import "AlbumController.h"

#import "PhotoSource.h"

#import "Photo.h"

#import "AlbumInfo.h"

#import "AlbumDatabase.h"



@implementation AlbumController



@synthesize albumName;

@synthesize urlAddress;



@synthesize images;



- (void)viewDidLoad

{

[super viewDidLoad];

// NSLog(@"%@", self.urlAddress);



[self createPhotos]; // method to set up the photos array

self.photoSource = [[PhotoSource alloc]

initWithType:PhotoSourceNormal

title:self.albumName

photos:images

photos2:nil];





self.navigationController.navigationBar.tintColor = [UIColor blackColor];



}



- (void)viewDidUnload

{

[super viewDidUnload];



// release and set to nil

}



-(void)createPhotos

{

if ([stories count] == 0)

{



NSString *path = self.urlAddress;

[self parseXMLFileAtURL:path];

}





images = [NSMutableArray arrayWithCapacity:[stories count]]; // needs to be mutable



for (int i = 0; i < [stories count]; i++)

{

NSString *img = [[stories objectAtIndex:i] objectForKey:@"image"];

img = [img stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];



//NSString * caption = [[stories objectAtIndex:i] objectForKey:@"caption"];

//caption = [caption stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];



[images addObject:[[[Photo alloc] initWithURL:img smallURL:img size:CGSizeMake(320, 212)] autorelease]];

}

}





#pragma mark -

#pragma mark XML Parser Implementation



- (void)parserDidStartDocument:(NSXMLParser *)parser{

//NSLog(@"found file and started parsing");

}



- (void)parseXMLFileAtURL:(NSString *)URL

{

stories = [[NSMutableArray alloc] init];



//you must then convert the path to a proper NSURL or it won't work

NSURL *xmlURL = [NSURL URLWithString:URL];



// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error

// this may be necessary only for the toolchain

rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];



// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.

[rssParser setDelegate:self];



// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.

[rssParser setShouldProcessNamespaces:NO];

[rssParser setShouldReportNamespacePrefixes:NO];

[rssParser setShouldResolveExternalEntities:NO];

[rssParser parse];

}



- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {

NSString * errorString = [NSString stringWithFormat:@"Unfortunately it is not possible to load Pictures. Please check Internet Connection. (Error code %i )", [parseError code]];

//NSLog(@"error parsing XML: %@", errorString);



UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:@"Failed to load the feed." message:errorString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];

[errorAlert show];

[errorAlert release];

}



- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict

{

//NSLog(@"found this element: %@", elementName);

currentElement = [elementName copy];

if ([elementName isEqualToString:@"item"]) {

// clear out our story item caches...

item = [[NSMutableDictionary alloc] init];

currentCaption = [[NSMutableString alloc] init];

//currentThumbnail = [[NSMutableString alloc] init];

currentImage = [[NSMutableString alloc] init];

}

}



- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{

//NSLog(@"ended element: %@", elementName);

if ([elementName isEqualToString:@"item"]) {

// save values to an item, then store that item into the array...



//[item setObject:currentThumbnail forKey:@"thumbnail"];

//[item setObject:currentCaption forKey:@"caption"];

[item setObject:currentImage forKey:@"image"];



[stories addObject:[[item copy] autorelease]];

}

}



- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{



// save the characters for the current item...

if ([currentElement isEqualToString:@"thumbnail"]) {

//[currentThumbnail appendString:string];

}// else if ([currentElement isEqualToString:@"caption"]) {

//[currentCaption appendString:string];

//}

else if ([currentElement isEqualToString:@"image"]) {

[currentImage appendString:string];

}

}



- (void)parserDidEndDocument:(NSXMLParser *)parser {

NSLog(@"all done!");

NSLog(@"stories array has %d items", [stories count]);

}



- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation

{

if (toInterfaceOrientation == UIInterfaceOrientationPortrait ||

toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||

toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)

{

return YES;

}

else

{

return NO;

}



}







#pragma mark -

#pragma mark Memory Management



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



[currentElement release];

[rssParser release];

[stories release];

[item release];

[currentCaption release];

//[currentThumbnail release];

[currentImage release];

[images release];

[stories release];



[super dealloc];

}



@end







and here is the didSelectRowAtIndexPath thats pushing this view







- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

AlbumInfo *info = [_albumInfos objectAtIndex:indexPath.row];

AlbumController *albumController = [[AlbumController alloc] init];



albumController.urlAddress = info.address;

albumController.albumName = info.name;

[self.navigationController pushViewController:albumController animated:YES];

[albumController release];

}







Here is the code for AlbumController.h







#import <Foundation/Foundation.h>

#import "Three20/Three20.h"



@interface AlbumController : TTThumbsViewController <NSXMLParserDelegate>

{

NSString *albumName;

NSString *urlAddress;



// images

NSMutableArray *images;



// parser

NSXMLParser * rssParser;

NSMutableArray * stories;

NSMutableDictionary * item;

NSString * currentElement;

NSMutableString * currentImage;

NSMutableString * currentCaption;



}



@property (nonatomic, strong) NSString *albumName;

@property (nonatomic, strong) NSString *urlAddress;



@property (nonatomic, retain) NSMutableArray *images;



- (void)createPhotos;

- (void)parseXMLFileAtURL:(NSString *)URL;



@end







used this tutorial http://www.raywenderlich.com/1430/how-to-use-the-three20-photo-viewer





Need help solving this memory leak and need to know why its crashing.





Thanks


Comments

  1. Simple. In Xcode 4.0+, Just click-hold on the Run icon, and press Profile. It'll open up Instruments, and you'll want Zombies. Then navigate your app to where the crash happened before, and this time, it'll show up in Instruments with the caller, and all the information about it.

    ReplyDelete
  2. The memory leak in viewDidLoad is caused by the following line:

    self.photoSource = [[PhotoSource alloc]
    initWithType:PhotoSourceNormal
    title:self.albumName
    photos:images
    photos2:nil];


    [PhotoSource alloc] returns an object you own (with a retain count of +1).
    initWithType:title:photos:photos2: does not change the retain count.

    So viewDidLoad is left with an object it owns, but no pointer to it. To balance the alloc you should send an autorelease message:

    self.photoSource = [[[PhotoSource alloc]
    initWithType:PhotoSourceNormal
    title:self.albumName
    photos:images
    photos2:nil] autorelease];

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex