我正在开发一个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/