2014-01-28 119 views
2

我有一种方法可以创建NSURLRequest,并用NSURLConnection方法sendAsynchronousRequest:queue:compltionHandler:发送该请求。这在我获取json文件或图像数据时工作正常,但是当我尝试读取XML文档时,发生了一些非常奇怪的事情。该方法正在被调用,但从来没有响应,所以完成处理程序永远不会被调用。有谁知道如何解决这一问题?我已经使用了这种方法数百次,但我从未见过这种行为。这里就是我所说的sendAsynchronousRequest:queue:compltionHandler:NSURLConnection sendAsynchronousRequest没有得到响应

- (void)getCachedFile:(NSString *)title withCompletion:(void (^)(NSData *data))completion 
{ 
    Reachability *reach = [Reachability reachabilityForInternetConnection]; 
    NetworkStatus status = [reach currentReachabilityStatus]; 
    if (status == NotReachable) 
    { 
     // read data locally 
     NSError *error = nil; 
     NSData *data = [NSData dataWithContentsOfFile:[self filePath:title] 
               options:NSDataReadingUncached 
               error:&error]; 
     if (error) 
     { 
      NSLog(@"COULD NOT READ LOCAL CACHED DATA: %@", error.localizedDescription); 
     } 
     else 
     { 
      completion(data); 
     } 
    } 
    else 
    { 
     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:title] 
               cachePolicy:NSURLRequestUseProtocolCachePolicy 
              timeoutInterval:30.0f]; 

     // get data from NSURLCache 
     NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; 
     if (cachedResponse) 
     { 
      // if the data is found in the response, use it 
      completion([cachedResponse data]); 
     } 
     else 
     { 
      // get the data from the server 
      [NSURLConnection sendAsynchronousRequest:request 
               queue:[NSOperationQueue currentQueue] 
            completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 
             if (connectionError) 
             { 
              NSLog(@"ERROR CONNECTING DATA FROM SERVER: %@", connectionError.localizedDescription); 
             } 
             else 
             { 
              [self.writingOperationQueue addOperationWithBlock:^{ 
              [[NSFileManager defaultManager] createFileAtPath:[self filePath:title] 
                        contents:data 
                       attributes:nil]; 
              }]; 
              completion(data); 
             } 
            }]; 
     } 
    } 
} 

回答

2

的几个注意事项一般方法: 为您的网络要求你完成块捕捉self。这将导致保留周期。

^(NSURLResponse *response, NSData *data, NSError *connectionError) { 
    if (connectionError) 
    { 
     NSLog(@"ERROR CONNECTING DATA FROM SERVER: %@", connectionError.localizedDescription); 
    } else { 
     [self.writingOperationQueue addOperationWithBlock:^{ 
      [[NSFileManager defaultManager] createFileAtPath:[self filePath:title] 
                contents:data 
                attributes:nil]; 
     }]; 
     completion(data); 
    } 
} 

要解决它,你应该声明块之前一个变量__weak MyClass *weakSelf = self;并且仅使用来自块内。

您的具体问题可能与您所调用的文档类型无关,并且更多地涉及您从中调用它的线索。您正在执行您的网络操作[NSOperationQueue currentQueue]。如果这是一个系统队列,它可能会在您的请求完成之前解除分配。您应该声明一个属性为NSOperationQueue并在其上执行所有网络请求。

[NSURLConnection sendAsynchronousRequest:request 
            queue:[NSOperationQueue currentQueue] 
         completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {...}]; 

应改为:

[NSURLConnection sendAsynchronousRequest:request 
            queue:self.networkOpQueue 
         completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {...}]; 
+0

这样的作品,感谢您的帮助! –

+3

我普遍同意,但有两个非常小的观察:1.在完成块中包含'self'不会在这种情况下引起强烈的参考周期。它只是在网络运营期间保留“自我”。 2.'sendAsynchronousRequest'中的'queue'不是网络操作发生的地方,而是运行完成块的地方。鉴于他正在保存'writingOperationQueue'(这很好),他可能只是使用'[NSOperationQueue mainQueue]'这样'complete'模块在主队列上运行(这对于UI和模型更新可能很重要)。 – Rob

+0

在这种情况下,您可以接受这些更改,但不是在任何情况下。我想确保它可以被广泛应用,即使在其他用户滥用它时也是如此。 – Holly