11

我在下载 5 MB 文件时遇到问题,在装有 iOS 6.1 的 iPhone 5 上需要 2 分钟以上。

使用相同 iOS 版本的 iPhone 4S 仅需 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但对我来说仍然无法正常工作。但是现在我更好地理解了这种奇怪的情况。

4

8 回答 8

1

Use AFDownloadRequestOperation (AFNetworking "sublass") - you can have also pause/resume operation.

Here you have an example https://stackoverflow.com/a/12209618

于 2013-03-24T04:50:28.227 回答
0

我会提出一个解决方案,其中您有某种具有NSOperationQueue它处理的通信管理器,使用单个入口点方法,您可以在其中为它提供您想要下载的内容所在的 URL,以及成功和失败块。通信管理器然后创建一个NSOperation您创建NSURLRequest和处理回调的位置。

一旦通信管理器将操作放入队列,它的start方法就会被调用。在我的通信管理器实现中,我通过 an 跟踪(除了将操作放入队列中)每个启动的操作,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

编辑 - Gist 示例文件

于 2013-06-10T06:40:14.067 回答
0

好吧,根据我的经验,AFNetworking在处理下载方面做得很好。我正在对 10+ MB 大小的文件使用下载操作。所以我强烈建议使用它。

我在堆栈上的答案以显示进度条。查看我实现两种方式的AFNetworking答案 NSUrlconnection分析它在下载时间中的变化。试试看

于 2013-06-10T09:27:18.053 回答
0

你试过AFNetworking吗?这是一个包装NSURLConnection。我不确定它是否会帮助您获得更快的下载速度,但它确实让您比NSURLConnection.

于 2013-03-23T18:48:08.570 回答
0

您使用 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];
});
于 2013-06-04T10:29:12.467 回答
0

只需尝试使用gzip将远程文件压缩为NSURLRequest. 它将大大加快您的连接速度。

要使用它,您需要将它安装在服务器上,好消息是如果您在apache2服务器上使用它,它会默认提供。要测试以确保您的服务器/URL 已gzip启用压缩,请使用此在线工具对其进行测试: http ://www.feedthebot.com/tools/gzip/

如果答案是肯定的,请继续在 Xcode 中将代码添加到您的 Objective-C 代码中。在代码中的这一行之后:

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用于小型NSURLRequestNSURLConnection任务。

于 2015-02-12T20:53:41.877 回答
-1

我认为这是您设备的问题。试试朋友的另一台设备。

于 2013-06-07T06:03:50.503 回答
-1

我不确定您的问题是什么,但以下代码对我来说可靠。

- (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];
    });

  }]];
}
于 2013-06-06T03:31:09.003 回答