私はエリカサドゥンの非同期ダウンロードの方法(プロジェクトファイルのリンク: download )を使用していますが、彼女の方法は大きなサイズ(50 mb以上)のファイルでは機能しません。 50 MBを超えるファイルをダウンロードしようとすると、通常、メモリクラッシュが原因でクラッシュします。とにかく、このコードを調整して大きなファイルでも機能するようにできますか?これは、DownloadHelperクラス(既にダウンロードリンクにあります)にあるコードです。
.h
@protocol DownloadHelperDelegate <NSObject>
@optional
- (void) didReceiveData: (NSData *) theData;
- (void) didReceiveFilename: (NSString *) aName;
- (void) dataDownloadFailed: (NSString *) reason;
- (void) dataDownloadAtPercent: (NSNumber *) aPercent;
@end
@interface DownloadHelper : NSObject
{
NSURLResponse *response;
NSMutableData *data;
NSString *urlString;
NSURLConnection *urlconnection;
id <DownloadHelperDelegate> delegate;
BOOL isDownloading;
}
@property (retain) NSURLResponse *response;
@property (retain) NSURLConnection *urlconnection;
@property (retain) NSMutableData *data;
@property (retain) NSString *urlString;
@property (retain) id delegate;
@property (assign) BOOL isDownloading;
+ (DownloadHelper *) sharedInstance;
+ (void) download:(NSString *) aURLString;
+ (void) cancel;
@end
.m
#define DELEGATE_CALLBACK(X, Y) if (sharedInstance.delegate && [sharedInstance.delegate respondsToSelector:@selector(X)]) [sharedInstance.delegate performSelector:@selector(X) withObject:Y];
#define NUMBER(X) [NSNumber numberWithFloat:X]
static DownloadHelper *sharedInstance = nil;
@implementation DownloadHelper
@synthesize response;
@synthesize data;
@synthesize delegate;
@synthesize urlString;
@synthesize urlconnection;
@synthesize isDownloading;
- (void) start
{
self.isDownloading = NO;
NSURL *url = [NSURL URLWithString:self.urlString];
if (!url)
{
NSString *reason = [NSString stringWithFormat:@"Could not create URL from string %@", self.urlString];
DELEGATE_CALLBACK(dataDownloadFailed:, reason);
return;
}
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
if (!theRequest)
{
NSString *reason = [NSString stringWithFormat:@"Could not create URL request from string %@", self.urlString];
DELEGATE_CALLBACK(dataDownloadFailed:, reason);
return;
}
self.urlconnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (!self.urlconnection)
{
NSString *reason = [NSString stringWithFormat:@"URL connection failed for string %@", self.urlString];
DELEGATE_CALLBACK(dataDownloadFailed:, reason);
return;
}
self.isDownloading = YES;
// Create the new data object
self.data = [NSMutableData data];
self.response = nil;
[self.urlconnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
- (void) cleanup
{
self.data = nil;
self.response = nil;
self.urlconnection = nil;
self.urlString = nil;
self.isDownloading = NO;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse
{
// store the response information
self.response = aResponse;
// Check for bad connection
if ([aResponse expectedContentLength] < 0)
{
NSString *reason = [NSString stringWithFormat:@"Invalid URL [%@]", self.urlString];
DELEGATE_CALLBACK(dataDownloadFailed:, reason);
[connection cancel];
[self cleanup];
return;
}
if ([aResponse suggestedFilename])
DELEGATE_CALLBACK(didReceiveFilename:, [aResponse suggestedFilename]);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData
{
// append the new data and update the delegate
[self.data appendData:theData];
if (self.response)
{
float expectedLength = [self.response expectedContentLength];
float currentLength = self.data.length;
float percent = currentLength / expectedLength;
DELEGATE_CALLBACK(dataDownloadAtPercent:, NUMBER(percent));
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// finished downloading the data, cleaning up
self.response = nil;
// Delegate is responsible for releasing data
if (self.delegate)
{
NSData *theData = [self.data retain];
DELEGATE_CALLBACK(didReceiveData:, theData);
}
[self.urlconnection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[self cleanup];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
self.isDownloading = NO;
NSLog(@"Error: Failed connection, %@", [error localizedDescription]);
DELEGATE_CALLBACK(dataDownloadFailed:, @"Failed Connection");
[self cleanup];
}
+ (DownloadHelper *) sharedInstance
{
if(!sharedInstance) sharedInstance = [[self alloc] init];
return sharedInstance;
}
+ (void) download:(NSString *) aURLString
{
if (sharedInstance.isDownloading)
{
NSLog(@"Error: Cannot start new download until current download finishes");
DELEGATE_CALLBACK(dataDownloadFailed:, @"");
return;
}
sharedInstance.urlString = aURLString;
[sharedInstance start];
}
+ (void) cancel
{
if (sharedInstance.isDownloading) [sharedInstance.urlconnection cancel];
}
@end
そして最後に、これは私がその上の2つのクラスでファイルを書く方法です:
- (void) didReceiveData: (NSData *) theData
{
if (![theData writeToFile:self.savePath atomically:YES])
[self doLog:@"Error writing data to file"];
[theData release];
}
誰かが私を助けてくれたら私はとても嬉しいです!
おかげで、
ケビン
インメモリを置き換えるNSData *data
とNSOutputStream *stream
。 -start
追加して開くストリームを作成します。
stream = [[NSOutputStream alloc] initToFileAtPath:path append:YES];
[stream open];
データが入ったら、ストリームに書き込みます。
NSUInteger left = [theData length];
NSUInteger nwr = 0;
do {
nwr = [stream write:[theData bytes] maxLength:left];
if (-1 == nwr) break;
left -= nwr;
} while (left > 0);
if (left) {
NSLog(@"stream error: %@", [stream streamError]);
}
完了したら、ストリームを閉じます。
[stream close];
より良いアプローチは、データivarに加えてストリームを追加し、ヘルパーをストリームのデリゲートとして設定し、着信データをデータivarにバッファーし、ストリームがヘルパーにスペースを送信するたびに、データivarのコンテンツをヘルパーにダンプすることです。利用可能なイベントとそれをデータivarから消去します。
上記のコードを少し変更しました。
この関数を使用すると、私にとってはうまくいきます。
- (void) didReceiveData: (NSData*) theData
{
NSOutputStream *stream=[[NSOutputStream alloc] initToFileAtPath:self.savePath append:YES];
[stream open];
percentage.hidden=YES;
NSString *str=(NSString *)theData;
NSUInteger left = [str length];
NSUInteger nwr = 0;
do {
nwr = [stream write:[theData bytes] maxLength:left];
if (-1 == nwr) break;
left -= nwr;
} while (left > 0);
if (left) {
NSLog(@"stream error: %@", [stream streamError]);
}
[stream close];
}
AFNetworking を試してください。そして:
NSString *yourFileURL=@"http://yourFileURL.Zip";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:yourFileURL]];
AFURLConnectionOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSString *cacheDir = [NSSearchPathForDirectoriesInDomains
(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [cacheDir stringByAppendingPathComponent:
@"youFile.Zip"];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:filePath append:NO];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
//show here your downloading progress if needed
}];
[operation setCompletionBlock:^{
NSLog(@"File successfully downloaded");
}];
[operation start];