【问题标题】:Memory warning in the iPad 1st generation and crash第 1 代 iPad 中的内存警告和崩溃
【发布时间】:2012-10-12 07:59:27
【问题描述】:

我正在开发一个具有下载书籍功能的 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;
}

如何避免崩溃?谢谢

【问题讨论】:

    标签: objective-c ios ziparchive


    【解决方案1】:

    编辑:

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

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

    希望对你有帮助。

    旧答案:

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

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

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

    【讨论】:

    • 感谢您的回答,我正在分析我的应用程序。你认为我应该传给 ARC 吗?
    • 如果自动转换有效,您可以尝试将您的应用转换为 ARC,看看情况是否有所改善。但是 ARC 并不是解决内存问题的灵丹妙药,它只是避免了最明显的错误。无论如何,如果我没记错的话,Xcode 4 可以重构您的代码以与 ARC 一起使用,所以请试一试……顺便问一下,哪些是 profiling 的结果?
    • 有 3 个泄漏,但 ZipArchive 没有,解压缩应用程序崩溃并向我显示内存分配中的内存警告。我不明白该怎么办。我用个人资料图片编辑了我的问题。
    • 我已经对我的应用程序进行了配置文件,问题不在于 ZipArchibe,而是与控制 .zip 的 md5 的其他功能有关,我已经注意内存。花了一天时间对此进行调试,如果他们将在 iPad 1st G 中进行测试,最终被 Apple 拒绝。谢谢@sergio。
    • @Mouh Ali,我不明白你是否解决了这个问题......如果没有,请提供有关您发现的违规功能的更多详细信息。
    【解决方案2】:

    我不同意塞尔吉奥的观点。

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

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

    【讨论】:

    • 感谢您的回答,但在我编辑之前,sergio 已经回答了我的问题。
    • 但我认为如果我拆分存档 md5 不一样?
    • 不,因为您实际上不会将整个文件加载到内存中...您正在尝试加载一个 180 mb 的对象,因此系统需要分配 180mb 的内存来加载该对象。它在 iPad 第一代中根本失败。如果你拆分它,内存操作只会发生在拆分文件中,而其余操作将发生在系统存储上……看看这个stackoverflow.com/a/6110216/312312
    猜你喜欢
    • 2012-03-06
    • 2011-09-12
    • 2011-10-15
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 2013-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多