Я работаю с приложением для отображения продукта, но у него есть утечка памяти, которая вызывает его сбой после загрузки слишком большого количества категорий.Приложение работает через SplitViewController, который перечисляет категории внизу слева, а после нажатия изображения продукта отображаются в detailViewController справа.Выбор категории за категорией в конечном итоге приводит к сбою приложения.
Я использовал инструменты -> инструмент «Утечки», чтобы отследить проблему, и мне сказали, что NSString appendString - утечка.Количество пропущенных строк, кажется, соответствует количеству продуктов в выбранной категории, поэтому я предполагаю, что один из моих циклов содержит проблему, но, поиграв с AutoreleasePools, я еще не решил ее.
Мойcode: этот метод вызывается, когда категория выбирается и анализирует XML-документ
- (NSMutableArray*) processXML{
//NSAutoreleasePool *pool4 = [[NSAutoreleasePool alloc] init];
// Initialize the productEntries MutableArray declared in the header
products = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSMutableString *documentsDirectory = [[NSMutableString stringWithFormat:@"%@", [paths objectAtIndex: 0]] autorelease];
// paths to save inputs to
NSString *productsFile = [documentsDirectory stringByAppendingFormat: @"/products2.xml"];
NSData *data = [NSData dataWithContentsOfFile: productsFile];
// Create a new rssParser object based on the TouchXML "CXMLDocument" class, this is the object that actually grabs and processes the RSS data
NSError *error = nil;
CXMLDocument *rssParser = [[[CXMLDocument alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding options:0 error:&error] autorelease];
// Create a new Array object to be used with the looping of the results from the rssParser
NSArray *resultNodes = NULL;
//NSString *xPathStart, *xPathEnd, *category, *finalStr;
NSString *xPathStart = [[NSString stringWithFormat:@""] autorelease];
NSString *xPathEnd = [[NSString stringWithFormat:@""] autorelease];
NSString *category = [[NSString stringWithFormat:@""] autorelease];
NSString *finalStr = [[NSString stringWithFormat:@""] autorelease];
NSString *detailStr = [[NSString stringWithFormat: detailItem] autorelease];
// category to be parsed - build up xPath expression
if([detailStr isEqualToString: @"On Order Stock"]) {
xPathStart = @"/products/product[instock='2";
xPathEnd = @"']";
finalStr = [NSString stringWithFormat:@"%@%@", xPathStart, xPathEnd];
} else {
xPathStart = @"/products/product[category='";
category = detailItem;
xPathEnd = @"']";
finalStr = [NSString stringWithFormat:@"%@%@%@", xPathStart, category, xPathEnd];
}
resultNodes = [rssParser nodesForXPath: finalStr error:nil];
// Loop through the resultNodes to access each items actual data
for (CXMLElement *resultElement in resultNodes) {
Product *productItem = [[Product alloc] init];
[productItem setCode: [[[resultElement childAtIndex: 1] stringValue] autorelease]];
[productItem setImage: [[[resultElement childAtIndex: 5] stringValue] autorelease]];
// Add the product object to the global productEntries Array so that the view can access it.
[products addObject: productItem];
[productItem release];
}
//[pool4 release];
return products;
}
Как вы можете видеть, я немного с ума сошел с autoReealse в моих строках.Другой сегмент кода, который отображает изображения, может быть проблемой, хотя Leaks действительно упоминает processXML напрямую.
- (void) displayImages:(NSMutableArray *)anArray {
// create scrollView object
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 100)];
scrollView.pagingEnabled = NO;
scrollView.scrollEnabled = YES;
scrollView.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1];
scrollView.userInteractionEnabled = YES;
//create info area below scrollView
infoView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 100, self.view.frame.size.width, 100)];
[infoView setContentSize:CGSizeMake(self.view.frame.size.width, 100)];
infoView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
infoView.scrollEnabled = NO;
[barcodeImgView setImage:[UIImage imageNamed:@"barcode2.jpg"]];
[infoView addSubview:codeLbl];
[infoView addSubview:nameLbl];
[infoView addSubview:priceLbl];
[infoView addSubview:dimensionsLbl];
[infoView addSubview:stockLbl];
[infoView addSubview:commentsLbl];
[infoView addSubview:barcodeImgView];
infoView.userInteractionEnabled = YES;
[codeLbl setText:[[NSString stringWithFormat:@""] autorelease]];
[nameLbl setText:[[NSString stringWithFormat:@""] autorelease]];
[priceLbl setText:[[NSString stringWithFormat:@""] autorelease]];
[commentsLbl setText:[[NSString stringWithFormat:@""] autorelease]];
[stockLbl setText:[[NSString stringWithFormat:@""] autorelease]];
[dimensionsLbl setText:[[NSString stringWithFormat:@""] autorelease]];
// hold x and y of each image
int x = 30;
int y = 50;
int noOfImages = [anArray count];
int maxRowWidth = (noOfImages / 3) + 1;
int xcount = 0; // position across the row, reset to zero and drop image down when equal to (noOfImages / 3) + 1
//NSAutoreleasePool *displayPool = [[NSAutoreleasePool alloc] init];
for(int i = 0; i < noOfImages; i++) {
// declare Product object to hold items in anArray
Product *prod = [[Product alloc] init];
prod = [anArray objectAtIndex: i];
// try for image in Documents folder, later checks it exists and if not uses Resource location
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSMutableString *documentsDirectory = [[NSString stringWithFormat:@"%@", [paths objectAtIndex: 0]] autorelease];;
// paths to save inputs to
NSString *imgName = [[NSString stringWithFormat:@"%@/%@", documentsDirectory, [prod image]] autorelease];
NSString *productName = [[NSString stringWithFormat:@"%@", [prod code]] autorelease];
// create and size image
UIImage *image = [UIImage imageWithContentsOfFile: imgName];
// set up button
UIButton *button= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:@selector(imageButtonClick:) forControlEvents:(UIControlEvents)UIControlEventTouchDown];
[button setTitle:productName forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize: 0];
[button setTitleColor: [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1] forState: UIControlStateNormal];
CGSize imageSize = image.size;
CGFloat height = imageSize.height;
CGFloat width = imageSize.width;
CGFloat ratio = 160 / width; // get ratio to divide height by
UIGraphicsBeginImageContext(CGSizeMake((height * ratio),160));
CGContextRef context = UIGraphicsGetCurrentContext();
[image drawInRect: CGRectMake(0, 0, height * ratio, 160)];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// create frame for image
CGRect newFrame = CGRectMake(x, y, 160,160);
UILabel *codeLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, y - 20, 170, 20)];
codeLabel.text = productName;
codeLabel.textColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
codeLabel.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1];
[button setFrame: newFrame];
[button setBackgroundImage:smallImage forState:UIControlStateNormal];
[scrollView setContentSize:CGSizeMake((maxRowWidth * 160) + 160,self.view.frame.size.height - 100)];
[self.scrollView addSubview:button];
[self.scrollView addSubview:codeLabel];
xcount++;
x = x + 170; // move across the page
if(xcount == maxRowWidth) {
y = y + 210; // move down the screen for the next row
x = 30; // reset x to left of screen
xcount = 0; // reset xcount;
}
[prod release];
}
//[displayPool release];
[self.view addSubview: scrollView];
[self.view addSubview: infoView];
[scrollView release];
[infoView release];
[pool release];
}
Кстати, пул - это autoreleasePool, определенный в h-файле длякласс.
Я был бы очень признателен за любую конкретную помощь относительно моего кода или общие советы о том, что может быть не так.