Ich verwende Erica Saduns Methode der asynchronen Downloads (Link hier für die Projektdatei: download), aber ihre Methode funktioniert nicht mit Dateien, die eine große Größe (50 MB oder höher) haben. Wenn ich versuche, eine Datei über 50 MB herunterzuladen, stürzt sie normalerweise aufgrund eines Speicherabsturzes ab. Kann ich diesen Code trotzdem optimieren, damit er auch mit großen Dateien funktioniert? Hier ist der Code, den ich in den Download Klassen haben (die bereits in den Download-Link):Herunterladen einer großen Datei - iPhone SDK
.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
Und schließlich ist dies, wie ich das schreiben Datei mit den zwei Klassen darüber:
- (void) didReceiveData: (NSData *) theData
{
if (![theData writeToFile:self.savePath atomically:YES])
[self doLog:@"Error writing data to file"];
[theData release];
}
Wenn jemand mir helfen könnte, wäre ich so froh!
Danke,
Kevin
Ich schrieb eine Bibliothek dafür mit der Methode, die Sie beschrieben haben. Ich setze es hier in der Hoffnung, dass es für einige Leute nützlich sein wird, oder inspiriere sie, ihre eigene Lösung zu schreiben. Wenn Sie damit natürlich einverstanden sind. https://github.com/thibaultCha/TCBlobDownload – thibaultcha