我正在开发一款具有下载书籍功能的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;
}
我怎样才能避免崩溃?感谢
答案 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存档拆分为较小的部分并逐个处理。