Używam metody Asynchronicznego pobierania Erica Sadun (link tutaj dla pliku projektu: download), jednak jej metoda nie działa z plikami o dużym rozmiarze (50 MB lub więcej). Jeśli spróbuję pobrać plik o rozmiarze przekraczającym 50 MB, zwykle będzie on ulegał awarii z powodu awarii pamięci. Czy mimo to mogę zmodyfikować ten kod, aby działał również z dużymi plikami? Oto kod mam w klasach DownloadHelper (który jest już w link do pobrania):Pobieranie dużego pliku - 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
I wreszcie to, jak piszę plik z dwiema klasami powyżej:
- (void) didReceiveData: (NSData *) theData
{
if (![theData writeToFile:self.savePath atomically:YES])
[self doLog:@"Error writing data to file"];
[theData release];
}
Jeśli ktoś mógłby mi pomóc, byłbym bardzo zadowolony!
Dzięki,
Kevin
Napisałem do tego bibliotekę, używając opisanej metody. Umieszczam to tutaj mając nadzieję, że przyda się to niektórym ludziom lub zainspiruje ich do napisania własnego rozwiązania. Jeśli oczywiście nie masz nic przeciwko temu. https://github.com/thibaultCha/TCBlobDownload – thibaultcha