iPad第一代和崩溃时的内存警告

时间:2012-10-12 07:59:27

标签: objective-c ios ziparchive

我正在开发一款具有下载书籍功能的iPad应用程序。书的大小约为180 Mo.书籍在服务器中,并且扩展名为.zip。我下载了这本书(.zip)然后我解压缩然后删除了.zip。我这样做:

- (BOOL)downloadBookWithRequest:(BookDownloadRequest*)book
{
    if (![book isValid])
    {
        NSLog(@"Couldn't launch download since request had missing parameter");
        return NO;
    }

    if ([self bookIsCurrrentlyDownloadingWithID:book.ID]) {
        NSLog(@"Book already downloaded");
        return NO;
    }

    ASIHTTPRequest *download = [[ASIHTTPRequest alloc] initWithURL:book.URL];

    download.userInfo = book.dictionary;
    download.downloadDestinationPath = [self downloadPathForBookID:book.ID];
    download.downloadProgressDelegate = self.downloadVC.downloadProgress;
    download.shouldContinueWhenAppEntersBackground = YES;

    [self.downloadQueue addOperation:download];

    [download release];

    // Update total requests
    self.requestsCount++;
    [self refreshDownloadsCount];

    if(self.downloadQueue.isSuspended)
        [self.downloadQueue go];

    [self.downloadVC show];

    return YES;
}



- (void)requestFinished:(ASIHTTPRequest*)request
{

    NSString *bookStoragePath = [[BooksManager booksStoragePath] stringByAppendingPathComponent:request.downloadDestinationPath.lastPathComponent.stringByDeletingPathExtension];
    NSString *bookZipPath = request.downloadDestinationPath;

    // Tell not to save the zip file into iCloud
    [BooksManager addSkipBackupAttributeToItemAtPath:bookZipPath];


    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *removeExistingError = nil;

    if ([fileManager fileExistsAtPath:bookStoragePath])
    {

        [fileManager removeItemAtPath:bookStoragePath error:&removeExistingError];

        if (removeExistingError)
        {
            [self bookDidFailWithRequest:request errorMessageType:DownloadErrorTypeFILE_ERROR];

            NSLog(@"ERROR: Couldn't remove existing book to unzip new download (%@)", removeExistingError);
        } else
            NSLog(@"INFO: Removed existing book to install new download");
    }

    ZipArchive* zip = [[ZipArchive alloc] init];

    if([self isCompatibleWithFileAtPath:bookZipPath] && [zip UnzipOpenFile:bookZipPath])
    {
        BOOL unzipSucceeded = [zip UnzipFileTo:bookStoragePath overWrite:YES];

        if (!unzipSucceeded)
        {
            [self bookDidFailWithRequest:request errorMessageType:DownloadErrorTypeFILE_ERROR];

            NSLog(@"ERROR: Couldn't unzip file %@\n to %@",bookZipPath,bookStoragePath);
        } else {
             [self bookDidInstallWithRequest:request];
            NSLog(@"INFO: Successfully unziped downloaded file");
        }
        [zip UnzipCloseFile];
    }
    else
    {
        [self bookDidFailWithRequest:request errorMessageType:DownloadErrorTypeFILE_ERROR];

        NSLog(@"ERROR: Unable to open zip file %@\n",bookZipPath);
    }

    [self removeZipFileAtPath:bookZipPath];
    [zip release];
}

-(BOOL) removeZipFileAtPath:(NSString*) bookZipPath {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:bookZipPath])
    {
        NSError *removeZipFileError = nil;

        [fileManager removeItemAtPath:bookZipPath error:&removeZipFileError];

        if (removeZipFileError) {
            NSLog(@"ERROR: Couldn't remove existing zip after unzip (%@)", removeZipFileError);
            return NO;
        }

        else {
            NSLog(@"INFO: Removed zip downloaded after unzip");
            return YES;
        }        
    }
    return NO;
}

我的问题是:此代码在iPhone 4 / iPhone 4s / iPad 2G / iPad3G上运行良好,但它与iPad第一代(解压缩书籍时)崩溃,崩溃记者说是内存警告。 / p>

问题是,如何优化此代码以避免内存警告并避免崩溃?谢谢你的回答;

编辑:我发现问题是由这部分代码引起的:

NSData *bookData = [[NSData alloc]initWithContentsOfFile:bookPath];

bookPath是.zip(约180 Mo)的路径,当我在iPad 1G时,此行崩溃我的应用程序,即:我收到内存警告,系统终止应用程序。你知道我怎么能避免这种情况。我用这行来计算书的MD5(.zip)

我在NSData中有一个这样的类别:

#import <CommonCrypto/CommonDigest.h>

@implementation NSData(MD5)

- (NSString*)MD5
{
    // Create byte array of unsigned chars
  unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];

    // Create 16 byte MD5 hash value, store in buffer
  CC_MD5(self.bytes, self.length, md5Buffer);

    // Convert unsigned char buffer to NSString of hex values
  NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
  for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) 
        [output appendFormat:@"%02x",md5Buffer[i]];

  return output;
}

我怎样才能避免崩溃?感谢

2 个答案:

答案 0 :(得分:1)

编辑:

因此,似乎罪魁祸首是将整个文件加载到内存中以计算其MD5哈希值。

解决这个问题的方法是计算MD5,而不必将整个文件加载到内存中。您可以查看this post,了解如何使用相关代码有效地计算MD5或SHA1哈希值。或者如果您愿意,可以直接转到github并获取代码。

希望它有所帮助。

老答案:

您应该检查您的应用程序,尤其是ZipArchive类,以查找内存泄漏或未释放的内存。您可以使用仪器的泄漏和内存分配工具来分析您的应用程序。

iPad1与其他设备之间的不同行为的解释可能与其不同的内存占用,以及设备的不同内存占用状态(例如,当您运行应用程序时,iPad 1的可用内存较少然后iPad 2,因为您在iPad 1上运行的状态其他应用程序离开了设备)。您可能会想到重新启动iPad 1以检查其行为是否刚刚开始。

在任何情况下,除了对不同行为的可能解释之外,最终的原因是您的应用程序如何管理内存,而仪器是最佳选择。

答案 1 :(得分:0)

我不同意塞尔吉奥。

您说当使用180mb zip存档启动NSData对象时,应用程序崩溃了。 嗯,很自然你的内存不足,因为第一代iPad拥有第二代内存的一半......(256MB vs 512)

解决方案是将zip存档拆分为较小的部分并逐个处理。

相关问题