Я хотел бы загрузить файлы непосредственно от URL до диска с помощью цели-c на iPhone OS.
В настоящее время я использую NSURLConnection для отправки synchronousRequest, пишущий возвращенный NSData в файл.
Как я могу изменить обработку загрузки (все еще имеющий запрос, являющийся синхронным, это уже находится в фоновом потоке) записать данные непосредственно в диск, не используя переменные памяти для хранения полного содержания (только мелкие детали)?
Пример кода ценился бы.
Спасибо всем заранее за Ваши ответы!
Вы можете это сделать, но это немного сложно настроить. Вот как бы я это сделал:
предупреждение: следующий код был набран в браузере и скомпилирован в моей голове. Кроме того, здесь не так много обработки ошибок. Будьте внимательны, разработчик.
//NSURLConnection+DirectDownload.h
@interface NSURLConnection (DirectDownload)
+ (BOOL) downloadItemAtURL:(NSURL *)url toFile:(NSString *)localPath error:(NSError **)error;
@end
//NSURLConnection+DirectDownload.m
@implementation NSURLConnection (DirectDownload)
+ (BOOL) downloadItemAtURL:(NSURL *)url toFile:(NSString *)localPath error:(NSError **)error {
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:url];
//configure the request, or leave it as-is
DirectDownloadDelegate * delegate = [[DirectDownloadDelegate alloc] initWithFilePath:localPath];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate];
[delegate autorelease];
[request release];
while ([delegate isDone] == NO) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
}
[connection release];
NSError * downloadError = [delegate error];
if (downloadError != nil) {
if (error != nil) { *error = [[downloadError retain] autorelease]; }
return NO;
}
return YES;
}
//DirectDownloadDelegate.h
@interface DirectDownloadDelegate : NSObject {
NSError *error;
NSURLResponse * response;
BOOL done;
NSFileHandle * outputHandle;
}
@property (readonly, getter=isDone) BOOL done;
@property (readonly) NSError *error;
@property (readonly) NSURLResponse * response;
@end
//DirectDownloadDelegate.m
@implementation DirectDownloadDelegate
@synthesize error, request, done;
- (id) initWithFilePath:(NSString *)path {
if (self = [super init]) {
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
}
[[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
outputHandle = [[NSFileHandle fileHandleForWritingAtPath:path] retain];
}
return self;
}
- (void) dealloc {
[error release];
[response release];
[outputHandle closeFile];
[outputHandle release];
[super dealloc];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)anError {
error = [anError retain];
[self connectionDidFinishLoading:connection];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)someData {
[outputHandle writeData:someData];
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse {
response = [aResponse retain];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
done = YES;
}
Основная идея состоит в том, что вы создаете стандартное NSURLConnection
, которое обычно является асинхронным, но просто блокируете поток, вращая цикл выполнения самостоятельно, пока соединение не будет установлено. Вы также можете использовать настраиваемый делегат подключения по URL-адресу, чтобы просто передать любые данные, получаемые подключением, непосредственно в файл.
Теперь вы можете сделать:
NSError * downloadError = nil;
BOOL ok = [NSURLConnection downloadItemAtURL:someURL toFile:someFile error:&downloadError];
if (!ok) {
NSLog(@"ack there was an error: %@", error);
} else {
NSLog(@"file downloaded to: %@", someFile);
}