objective-c - 第一代 iPad 中的内存警告和崩溃

标签 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 第一代上崩溃(解压缩本书时),崩溃报告者说这是内存警告。

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

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

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

如何避免崩溃?谢谢

最佳答案

编辑:

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

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

希望对您有所帮助。

旧答案:

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

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

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

关于objective-c - 第一代 iPad 中的内存警告和崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12854653/

相关文章:

ios - 如何在单个 UITableViewCell 中显示多个(任意)数量的标签(标签)?

objective-c - OAuthConsumer - 使用 OAMutableURLRequest 将图像发送到服务器

ios - SWRevealviewcontroller 嵌套 ViewController

iOS:如何查询WiFi状态

php - ZipArchive php 类 - 它是 PHP 内置的吗?

iOS表格 View 单元格高亮边框错误

iphone - Objective-C 中的 Javascript 样式对象

ios - 获取现有 UILocalNotifications 的列表并修改它们的日期

c++ - c++ 将多个文件压缩成一个文件

c# - Ziparchive:如何从 ziparchive 关闭创建的条目