簡體   English   中英

當我在滾動UITableview期間顯示文檔目錄中的圖像時,內存不斷增加然后應用程序崩潰

[英]Memory continuously increase then app crash when i display image from document directory during scrolling UITableview

我的要求是下載應用程序內存中的所有圖像,如果可用,則從本地顯示。

下面是我從本地訪問圖像的代碼,如果它不可用,那么它將下載然后顯示。

[cell.imgProfilePic processImageDataWithURLString:cData.PICTURE];

我已經制作了自定義UIImageView

DImageView.h

    #import <UIKit/UIKit.h>
    @interface DImageView : UIImageView
    @property (nonatomic, strong) UIActivityIndicatorView *activityView;
    - (void)processImageDataWithURLString:(NSString *)urlString;
    + (UIImage *)getSavedImage :(NSString *)fileName;
    @end

DImageView.m

#import "DImageView.h"
#define IMAGES_FOLDER_NAME  @"DImages"

@implementation DImageView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {    }
    return self;
}
- (void)dealloc
{
    self.activityView = nil;
    [super dealloc];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self)
    {
        [self initWithFrame:[self frame]];
    }
    return self;
}
- (void)processImageDataWithURLString:(NSString *)urlString
{
    @autoreleasepool
    {
    UIImage * saveImg =[DImageView getSavedImage:urlString];
    if (saveImg)
    {
        @autoreleasepool
        {
        dispatch_queue_t callerQueue = dispatch_get_main_queue();
        dispatch_async(callerQueue, ^{

            @autoreleasepool{
            [self setImage:saveImg];
            }
        });
    }
    }
    else
    {
        [self showActivityIndicator];
        NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

        dispatch_queue_t callerQueue = dispatch_get_main_queue();
        dispatch_queue_t downloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
        __block NSError* error = nil;
        dispatch_async(downloadQueue, ^{

            @autoreleasepool
            {
                NSData * imageData = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error];
                if (!error)
                {
                    dispatch_async(callerQueue, ^{
                        @autoreleasepool {
                        UIImage *image = [UIImage imageWithData:imageData];
                        [self setImage:image];
                        [self hideActivityIndicator];
                        [self saveImageWithFolderName:IMAGES_FOLDER_NAME AndFileName:urlString AndImage:imageData];
                        }
                    });
                }
            }
        });
        dispatch_release(downloadQueue);
    }
    }
}
- (void) showActivityIndicator
{
    self.activityView = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
    self.activityView.hidesWhenStopped = TRUE;
    self.activityView.backgroundColor = [UIColor clearColor];
    self.activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;

    [self addSubview:self.activityView];
    [self.activityView startAnimating];
}
- (void) hideActivityIndicator
{
    CAAnimation *animation = [NSClassFromString(@"CATransition") animation];
    [animation setValue:@"kCATransitionFade" forKey:@"type"];
    animation.duration = 0.4;;
    [self.layer addAnimation:animation forKey:nil];
    [self.activityView stopAnimating];
    [self.activityView removeFromSuperview];

    for (UIView * view in self.subviews)
    {
        if([view isKindOfClass:[UIActivityIndicatorView class]])
            [view removeFromSuperview];
    }
}
- (void)saveImageWithFolderName:(NSString *)folderName AndFileName:(NSString *)fileName AndImage:(NSData *) imageData
{
    @autoreleasepool{
    NSFileManager *fileManger = [[NSFileManager defaultManager] autorelease];
    NSString *directoryPath =  [[NSString stringWithFormat:@"%@/%@",[DImageView  applicationDocumentsDirectory],folderName] autorelease];

    if (![fileManger fileExistsAtPath:directoryPath])
    {
        NSError *error = nil;
        [fileManger createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error];
    }
    fileName = [DImageView fileNameValidate:fileName];
    NSString *filePath = [[NSString stringWithFormat:@"%@/%@",directoryPath,fileName] autorelease];

    BOOL isSaved = [imageData writeToFile:filePath atomically:YES];
    if (!isSaved)DLog(@" ** Img Not Saved");
    }
}

+ (NSString *)applicationDocumentsDirectory
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;
}

+ (UIImage *)getSavedImage :(NSString *)fileName
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    fileName = [DImageView fileNameValidate:fileName];

    NSFileManager * fileManger = [[NSFileManager defaultManager] autorelease];
    NSString * directoryPath =  [[NSString stringWithFormat:@"%@/%@",[DImageView applicationDocumentsDirectory],IMAGES_FOLDER_NAME] autorelease];
    NSString * filePath = [[NSString stringWithFormat:@"%@/%@",directoryPath,fileName] autorelease];

    if ([fileManger fileExistsAtPath:directoryPath])
    {
        UIImage *image = [[[UIImage imageWithContentsOfFile:filePath] retain]autorelease];
        if (image)
            return image;
        else
            return nil;
    }
    [pool release];
    return nil;
}

+ (NSString*) fileNameValidate : (NSString*) name
{
    name = [name stringByReplacingOccurrencesOfString:@"://" withString:@"##"];
    name = [name stringByReplacingOccurrencesOfString:@"/" withString:@"#"];
    name = [name stringByReplacingOccurrencesOfString:@"%20" withString:@""];
    return name;
}
@end

一切正常,平滑滾動以及后台的asyncImage下載。

問題是當我滾動UITableview應用程序內存不斷增加,經過一段時間后,我得到了Receive memory waring 2/3時間然后應用程序崩潰。

當我使用AsyncImageView類時,內存不會增加並且其工作正常。 但由於應用程序的要求,我將所有圖像保存到Document Directory並在其可用時顯示。

我已嘗試使用@autoreleasepoolrelease一些變量但未獲得成功。

我很感激,如果有人有解決方案來管理內存管理。

 **ARC is off in my application.** 

UIImagePNGRepresentation可能會返回非自動釋放的對象 - 您可以嘗試釋放它並查看是否會導致崩潰。 顯然你沒有發布一些東西,但除了圖像表示之外別無其他。

其他一些評論:

  • 使用ObjectAlloc工具在Instruments中運行您的應用程序,應該立即明確哪些對象未被釋放。 如果您不了解樂器,那么現在是時候學習它了。

  • 您可以“跟蹤”對象並在使用ObjectTracker解除分配時獲取消息 - 但它是專為ARC設計的,因此您可能需要對其進行調整。 如果您使用它,您將在每個對象被釋放時看到一條消息

  • 當表格視圖使用單元格完成時,您可以接收一個委托方法,告訴您這樣,然后您可以將單元格保留為nil(釋放)和對象

  • 你使用downloadQueue是奇怪的 - 在你的實例中創建一次作為ivar,根據需要使用它,並在dealloc發布它

  • 您隱藏主隊列上的活動微調器,但不要在主隊列上啟動它

  • 您命令活動視圖從超級視圖中刪除自己,但隨后在子視圖中查找並嘗試將其刪除:

[self.activityView removeFromSuperview];

for (UIView * view in self.subviews)
{
    if([view isKindOfClass:[UIActivityIndicatorView class]])
        [view removeFromSuperview];
}

最后,儀器就是你想要的。 你可以在這里閱讀更多關於它的信息,或者只是谷歌,你肯定會找到一大堆博客來閱讀。

是的,最后我已經解決了。

問題中的代碼現在正常工作。 但是如果沒有release一些對象和代碼中的@autoreleasepool塊,在滾動UITableView期間內存會不斷增加。

Instrument我發現UILableViewUIImageView中的內存增加。 我正在使用Custom UITableViewCell ,在該文件中我實現了dealloc方法。 所以當我在UITableViewCell .m文件中實現dealloc方法並releasenil all對象時。

在滾動TableView期間memory不增加並解決了問題。

根據我的理解,你的“getSavedImage”方法中存在一個問題,你必須手動管理內存而不是“自動釋放”,所以我的建議是使用

UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath]
and also release it after use of it. means after '[self setImage:saveImg];'
[saveImg release]

而不是這個。

[[UIImage imageWithContentsOfFile:filePath] retain];

'不要使用Autorelease,因為它一直停留在內存中,直到池沒有耗盡'而且正因為這樣你才會遇到內存問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM