Ответ 1
Использовать AFDownloadRequestOperation (AFNetworking "sublass" ) - вы можете также приостановить/возобновить работу.
Здесь у вас есть пример fooobar.com/questions/539490/...
У меня возникла проблема с загрузкой 5 Мбайт файла, это занимает более 2 минут на iPhone 5 с iOS 6.1.
Используя iPhone 4S с той же версией iOS, он занимает всего 10 секунд, оба используют WiFi.
Я пробовал различную политику и интервал тайм-аута NSURLRequest, он ничего не менял, он все еще занимает много времени. Загрузка осуществляется через HTTP.
Я использую класс NSURLConnection, перед загрузкой этого "большого" файла я загружаю два других.
Не знаю, что еще может быть важно, чтобы сократить время.
Спасибо заранее.
код:
@interface MyClass : NSObject <NSURLConnectionDelegate>
{
@private id delegate;
NSURLConnection *connection;
NSMutableData* responseData;
//...
}
#import "MyClass.h"
@implementation MyClass
-(void)getObj1:(id)delegateObj
{
delegate = delegateObj;
NSString *url = @"...";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(connection)
{
responseData = [NSMutableData data];
}
}
-(void)getObj2:(*String)somesString
{
NSString *url = @"...";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(connection)
{
responseData = [NSMutableData data];
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//....
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if(firstRequest)
{
//save data from first request and set responseData clear
[self getObj2:@"..."];
}
}
и другие, не имеющие ничего особенного, надеюсь, этого будет достаточно
Я нашел этот пост https://devforums.apple.com/message/754875#754875, но все еще не работает нормально для меня. Однако теперь я лучше понимаю эту странную ситуацию.
Использовать AFDownloadRequestOperation (AFNetworking "sublass" ) - вы можете также приостановить/возобновить работу.
Здесь у вас есть пример fooobar.com/questions/539490/...
Вы пробовали AFNetworking
? Это оболочка на NSURLConnection
. Я не уверен, поможет ли вам ускорить загрузку, но это наверняка даст вам преимущество над NSURLConnection
.
Вы использовали очередь GCD dispatch_async для выполнения набора запросов NSURLRequest для загрузки данных с сервера или получения ответа сервера.
NSString *webURL = @"http://therealurl.appspot.com/?format=json&url=bit.ly/a";
NSURL *url = [NSURL URLWithString:webURL];
NSURLRequest *awesomeRequest = [NSURLRequest requestWithURL:url];
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:awesomeRequest delegate:self];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
NSRunLoop *loop=[NSRunLoop currentRunLoop];
[connection scheduleInRunLoop:loop forMode:NSRunLoopCommonModes];
//[self processTheAwesomeness];
});
Я не уверен, в чем проблема, но следующий код работает для меня надежно.
- (id)init
{
self.downloadQueue = [[NSOperationQueue alloc] init];
[self.downloadQueue setMaxConcurrentOperationCount:1];
}
- (void)doDownload:(NSURL *)url
{
[self.downloadQueue addOperation:[NSBlockOperation blockOperationWithBlock:^{
NSData *data =[NSData dataWithContentsOfURL:url];
dispatch_sync(dispatch_get_main_queue(), ^{
NSAutoreleasePool *mainQueuePool = [[NSAutoreleasePool alloc] init];
... update user interface ...
[mainQueuePool release];
});
}]];
}
Я бы предложил решение, в котором у вас есть менеджер связей, который имеет NSOperationQueue
, который обрабатывает, с одним методом точки входа, где вы указываете ему URL-адрес, в котором находится контент, который вы хотите загрузить, и успех и отказ.
Менеджер связи создает NSOperation
, где вы создаете NSURLRequest
и обрабатываете обратные вызовы.
Как только менеджер связи отправит операцию в очередь, вызывается метод start
.
В моей реализации менеджера связи я отслеживаю (помимо ввода операций в очередь) каждой запущенной операции через NSMutableDictionary
, чтобы вы могли отменить одну или все операции (в примере кода, который используется для operationKey
для этого Здесь JSONOperation
возвращает (в случае успеха) NSString для коммуникатора, но это могут быть и любые типы данных, например, я использую один и тот же класс для загрузки изображений, поэтому я передал бы сам объект данных.
Ниже вы можете найти мой класс JSONOperation. Мне нравится идея, что я могу поместить другие файлы в Gist.
Мой NSOperation
выглядит следующим образом
@interface JSONOperation : NSOperation <NSURLConnectionDataDelegate, OperationDelegate>
+ (instancetype)jsonOperationForProvider:(id)provider success:(OperationSuccessWithString)success failure:(OperationFailure)failure;
@end
#import "JSONOperation.h"
#import "ProviderDelegate.h"
@interface JSONOperation()
@property (nonatomic, assign) BOOL executing;
@property (nonatomic, assign) BOOL finished;
@property (nonatomic, assign) BOOL cancelled;
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, weak) id <ProviderDelegate> delegate;
@property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, strong) NSMutableData *receivedData;
@property (nonatomic, copy) OperationFailure failure;
@property (nonatomic, copy) OperationSuccessWithString success;
@end
@implementation JSONOperation
- (void)start
{
if ([self isCancelled])
{
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"];
return;
}
NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[self.connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[self.connection start];
[self willChangeValueForKey:@"isExecuting"];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
}
- (NSMutableData *)receivedData
{
if (nil == _receivedData) {
_receivedData = [NSMutableData data];
}
return _receivedData;
}
+ (instancetype)jsonOperationForProvider:(id <ProviderDelegate>)provider success:(OperationSuccessWithString)success failure:(OperationFailure)failure
{
NSAssert(nil != provider, @"provider parameter can't be nil");
JSONOperation *operation = [[[self class] alloc] init];
operation.delegate = provider;
operation.url = provider.contentURL;
operation.failure = failure;
operation.success = success;
return operation;
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isExecuting {
return _executing;
}
- (BOOL)isFinished {
return _finished;
}
- (BOOL)isCancelled {
return _cancelled;
}
#pragma mark - NSURLConnectionDataDelegate
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (_success) {
NSString *receivedText = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
_receivedData = nil;
self.success(self, receivedText);
}
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[connection cancel];
_connection = nil;
_receivedData = nil;
_url = nil;
if (_failure) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.failure(self, error);
}];
}
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
#pragma mark - OperationDelegate
- (NSString *)operationKey
{
return [self.url absoluteString];
}
- (id)provider
{
return _delegate;
}
- (void)cancelOperation
{
_failure = nil;
_success = nil;
[self.connection cancel];
_connection = nil;
_receivedData = nil;
_url = nil;
[self willChangeValueForKey:@"isCancelled"];
[self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
_cancelled = YES;
[self didChangeValueForKey:@"isCancelled"];
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
@end
EDIT - Примеры файлов Gist
В моем опыте AFNetworking выполняет огромную работу по обработке загрузок. Я использую операцию загрузки файлов с размером 10+ МБ. Поэтому я настоятельно рекомендую использовать его.
Мой ответ в стеке, чтобы показать прогресс-панель. Отвечайте, где я реализую оба способа: AFNetworking
и NSUrlconnection
. Вы можете попробовать оба способа и можно увидеть прогресс, и вы можете рассчитать, как байты загружаются в каждом пакете. Отслеживайте его, чтобы вы могли анализировать, как он меняется во время загрузки.
Попробуйте
Просто попробуйте использовать gzip
для сжатия удаленного файла для NSURLRequest
. Это значительно ускорит ваше соединение.
Чтобы использовать это, вам необходимо установить его на сервере, и хорошая новость заключается в том, что вы используете apache2
на своем сервере, и он приходит по умолчанию. Чтобы проверить, чтобы ваш сервер/URL-адрес имел gzip
сжатие, проверьте его с помощью этого онлайн-инструмента:
http://www.feedthebot.com/tools/gzip/
Если да, перейдите к добавлению кода в код Objective-C в Xcode. После этой строки в вашем коде:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0];
просто добавьте это:
// Create a mutable copy of the immutable request and add more headers
NSMutableURLRequest *mutableRequest = [request mutableCopy];
//add gzip compression
[mutableRequest addValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
// Now set our request variable with an (immutable) copy of the altered request
request = [mutableRequest copy];
Это значительно ускорит ваше время отклика, и вам не нужно использовать AFNetworking
для небольшой задачи NSURLRequest
или NSURLConnection
.
Я думаю, что это проблема на вашем устройстве. Попробуйте другое устройство у друга.