0

我正在开发一个具有下载书籍功能的 iPad 应用程序。书籍大小约为 180 个月。书籍在服务器中,扩展名为 .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 上崩溃(解压缩书时),崩溃记者说这是内存警告。

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

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

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;
}

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

4

2 回答 2

1

编辑:

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

对此的解决方案是计算 MD5,而不必将整个文件加载到内存中。您可以看一下这篇文章,解释如何使用相关代码有效地计算 MD5 或 SHA1 哈希。或者如果你愿意,你可以直接去github并获取代码。

希望能帮助到你。

旧答案:

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

iPad1 与其他设备之间的不同行为的解释可能在于它们不同的内存占用,以及设备的不同内存占用状态(例如,当您运行应用程序时,iPad 1 的可用内存比 iPad 少2 因为您在 iPad 1 上运行的其他应用程序离开设备的状态)。您可能会考虑重新启动 iPad 1 以重新开始检查其行为。

无论如何,除了对不同行为的可能解释之外,最终原因是您的应用程序如何管理内存,而 Instruments 是要走的路。

于 2012-10-12T08:10:44.833 回答
0

我不同意塞尔吉奥。

您是说当您使用 180mb zip 存档初始化 NSData 对象时应用程序崩溃。嗯,内存不足是很自然的,因为第一代 iPad 的内存只有第二代的一半……(256MB vs 512)

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

于 2012-10-12T21:13:47.140 回答