2012-02-05 46 views
1

我使用three20來創建圖像查看器。首先,我從sql數據庫創建相冊列表,當用戶選擇任何相冊時,其url字符串將傳遞給此代碼,該代碼使用XML Parser在網絡上創建可用圖片的thums。一切工作正常,但用戶返回到專輯列表並選擇另一個專輯。應用程序崩潰'線程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]; 
} 

這裏使用本教程http://www.raywenderlich.com/1430/how-to-use-the-three20-photo-viewer

爲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 

代碼需要幫助解決這個內存泄漏,並需要知道爲什麼它的崩潰ING。

謝謝

+0

啓用NSZombie環境變量,看看你發送消息到發佈的對象。 self.photoSource有哪些屬性?保留還是分配? – 0x8badf00d 2012-02-06 00:30:12

+0

我還沒有申報self.photoSource的任何財產,你能指導我通過NSZombie的東西。以前從未使用過。 – Hitz 2012-02-06 03:18:02

+0

事情是,如果我從didSelectRowAtIndexPath中刪除albumController版本,那麼應用程序工作正常,但在產品分析期間,我得到內存泄漏。 – Hitz 2012-02-06 03:25:35

回答

0

簡單。在Xcode 4.0+中,只需單擊「運行」圖標並按「配置文件」即可。它會打開儀器,你會想要殭屍。然後將您的應用程序導航到之前發生崩潰的位置,這一次,它將顯示在與調用程序一起的樂器中,以及關於它的所有信息。

+0

我會檢查一下。謝謝 – Hitz 2012-02-08 01:42:03

0

在viewDidLoad中內存泄漏是由下面的行引起的:

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

[PhotoSource alloc]返回你自己的對象(具有+1的保留數)。 initWithType:title:photos:photos2:不會更改保留計數。

因此viewDidLoad剩下一個它擁有的對象,但沒有指向它的指針。爲了平衡你應該發送一個autorelease消息的分配:

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