我正在使用three20来创建图像查看器。首先我要从sql db创建专辑列表,当用户选择任何专辑时,其url字符串将传递给此代码,该代码使用XML Parser在网络上创建可用图片的thum。一切正常,但当用户返回专辑列表并选择另一个专辑。应用程序崩溃'主题1:程序收到信号:“EXC + BAD_ACCESS” main.m 。加上XCode产品分析可以在viewDidLoad中创建photoSource时发生潜在的内存泄漏。这是代码
#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
这里是推送此视图的didSelectRowAtIndexPath
- (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];
}
以下是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
使用了本教程http://www.raywenderlich.com/1430/how-to-use-the-three20-photo-viewer
需要帮助解决此内存泄漏问题并需要知道崩溃的原因。
由于
答案 0 :(得分:0)
简单。在Xcode 4.0+中,只需单击“运行”图标上的“按住”,然后按“配置文件”。它会打开乐器,你会想要僵尸。然后将您的应用程序导航到之前发生崩溃的位置,这次,它将显示在带有调用者的Instruments中,以及有关它的所有信息。
答案 1 :(得分:0)
viewDidLoad中的内存泄漏是由以下行引起的:
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:self.albumName
photos:images
photos2:nil];
[PhotoSource alloc]
返回您拥有的对象(保留计数为+1)。
initWithType:title:photos:photos2:
不会更改保留计数。
所以viewDidLoad
留下了它拥有的对象,但没有指向它的指针。要平衡alloc,您应该发送一个自动释放消息:
self.photoSource = [[[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:self.albumName
photos:images
photos2:nil] autorelease];