Question

I have a method that creates a NSURLRequest, and sends that request with the NSURLConnection method sendAsynchronousRequest:queue:compltionHandler:. This works fine when I am fetching json files or image data, but when I try to fetch an XML document, something really weird is happening. The method is being called, but there is never a response, so the completion handler is never called. Does anyone know how to fix this? I have used this method hundreds of times, but I have never seen this behavior. Here is the method where I call sendAsynchronousRequest:queue:compltionHandler:

- (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);
                                       }
                                   }];
        }
    }
}
Was it helpful?

Solution

A few notes generally: Your completion block for your network request is capturing self. This will cause retain cycles.

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

To fix it, you should declare a variable __weak MyClass *weakSelf = self; before the block and only use that from within the block.

Your specific problem likely has nothing do to with the type of document you are calling and more about what thread you're calling it from. You are performing your network operation on [NSOperationQueue currentQueue]. If this is a system queue, it is likely being deallocated before your request completes. You should declare a property that is an NSOperationQueue and perform all your network requests on it.

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

Should be changed into:

[NSURLConnection sendAsynchronousRequest:request
                                   queue:self.networkOpQueue
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {...}];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top