Chris Loonam
Chris Loonam

Reputation: 5745

iOS NSURLConnection not downloading files from certain URLs

I have an NSURLConnection in a tableview cell subclass that can download most files. I noticed, however, that some fail to start downloading, and time out. An example would be this URL, which is just a test zip file that downloads fine in any other browser. Heres my code for the download

-(void)downloadFileAtURL:(NSURL *)url{
    self.downloadedData = [[NSMutableData alloc] init];
    self.url = url;
    conn = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:self.url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:1200.0] delegate:self startImmediately:YES];
}

- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSHTTPURLResponse*)response
{
    int statusCode = [response statusCode];
    if (statusCode == 200){
        self.fileName.text = response.URL.lastPathComponent;
        self.respo = response;
        expectedLength = [response expectedContentLength];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    [self.downloadedData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    CFStringRef mimeType = (__bridge CFStringRef)[_respo MIMEType];
    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
    CFStringRef extension = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
    NSString *fileName = [NSString stringWithFormat:@"%@.%@", [[_respo suggestedFilename] stringByDeletingPathExtension], (__bridge NSString *)extension];
    [[NSFileManager defaultManager] createFileAtPath:[[self docsDir] stringByAppendingPathComponent:[NSString stringWithFormat:@"Downloads/%@", fileName]] contents:_downloadedData attributes:nil];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    NSLog(@"Download failed with error: %@", error);
}

Anybody see anything that might cause this?

Heres the error:

Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0x1fd2c650 
{NSErrorFailingURLStringKey=http://download.thinkbroadband.com/10MB.zip, 
NSErrorFailingURLKey=http://download.thinkbroadband.com/10MB.zip, 
NSLocalizedDescription=The request timed out., NSUnderlyingError=0x1fdc90b0 "The request timed out."}

Upvotes: 6

Views: 2440

Answers (7)

comeGetSome
comeGetSome

Reputation: 1963

accept any response with http response code range 200-299 and disable caching on the http-connector.

Upvotes: 0

warpedspeed
warpedspeed

Reputation: 1098

Do you have any libraries (TestFlight, UA, etc) in the project? Try removing them and re-test. We had an app that used NSUrlConnection with TestFlight SDK that caused all sorts of sporadic network problems.

NSURLConnection timing out

ASIHTTPRequest request times out

https://github.com/AFNetworking/AFNetworking/issues/307

Upvotes: -1

SAMIR RATHOD
SAMIR RATHOD

Reputation: 3510

try with HCDownloadViewController and you can check which url is not downloaded. and next time sync for that particular url which is not downloaded.

.h file

#import "HCDownloadViewController.h"
@interface HomeViewController_iPhone : UIViewController<HCDownloadViewControllerDelegate>
{
    HCDownloadViewController *tblDownloadHairStyle;

}
@property (nonatomic,retain) HCDownloadViewController *tblDownloadHairStyle;

.m file

#define kAppDirectoryPath   NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)

@synthesize tblDownloadHairStyle

- (void)viewDidLoad
{
    [super viewDidLoad];
     tblDownloadHairStyle=[[HCDownloadViewController alloc] init];
    tblDownloadHairStyle.delegate=self;
}
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSHTTPURLResponse*)response
{

    [self createDocumentDirectory:@"Downloaded_HairStyle"];
    NSString *pathHair=[self getDocumentDirectoryPath:@"Downloaded_HairStyle"];
    tblDownloadHairStyle.downloadDirectory = pathHair;
     ////You can put url in for loop, it create queue for downloading.
    [tblDownloadHairStyle downloadURL:[NSURL URLWithString:@"yourUrl"] userInfo:YourResponseDictonary];
}


-(void)createDocumentDirectory:(NSString*)pStrDirectoryName
{
    NSString *dataPath = [self getDocumentDirectoryPath:pStrDirectoryName];

    if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
        [[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:NULL];
}

-(NSString*)getDocumentDirectoryPath:(NSString*)pStrPathName
{
    NSString *strPath = @"";
    if(pStrPathName)
        strPath = [[kAppDirectoryPath objectAtIndex:0] stringByAppendingPathComponent:pStrPathName];

    return strPath;
}


#pragma mark-
#pragma mark-HCDownloadViewController Delegate Method
- (void)downloadController:(HCDownloadViewController *)vc startedDownloadingURL:(NSURL *)url userInfo:(NSDictionary *)userInfo {

}

- (void)downloadController:(HCDownloadViewController *)vc finishedDownloadingURL:(NSURL *)url toFile:(NSString *)fileName userInfo:(NSDictionary *)userInfo {

    if (vc==tblDownloadHairStyle) {
       if ([tblDownloadHairStyle numberOfDownloads]==0) {

            NSLog(@"AllDownLoad are complete");
         }
    }
}
- (void)downloadController:(HCDownloadViewController *)vc failedDownloadingURL:(NSURL *)url withError:(NSError *)error userInfo:(NSDictionary *)userInfo {
     NSLog(@"failedDownloadingURL=%@",url);
}

https://github.com/H2CO3/HCDownload

Upvotes: 0

CouchDeveloper
CouchDeveloper

Reputation: 19106

"I have an NSURLConnection in a tableview cell subclass " - never do this. As Sung-Pil Lim already pointed out correctly, TableView Cells will be reused which may cause this issue.

Anyway, the response data of your connection is a property of the model. The model might encapsulate how it gets to this data. If that data is not immediately available once it will be accessed, it should provide a "placeholder" value instead and start an asynchronous task which retrieves this data.

Suppose a model's property, an image, will be accessed by the view controller in order to be displayed by a view. The model has not yet loaded its actual image - and thus it returns a "placeholder image" in order to let the view display something. But at the same time the model is starting an asynchronous task to load the image. When this connection is finished loading with the data, the model updates internally its property - thereby replacing the placeholder with the real image. The update of the property should be performed on the main thread - since the UIKit views may access the same property as well.

During initialization, the View Controller has registered as an observer of the model's property (see KVO). When the model's property is updated, the controller gets notified. The View Controller then performs appropriate actions so that the view will be redrawn and displays the new updated value.

Your model should have a "cancel" method, which will be send to the model from the controller when the actual value of the model's property is not required anymore. For example, the user switched to another view (see viewWillDisappear).

Upvotes: 3

sangony
sangony

Reputation: 11696

I would start with a clean slate and just use basic code to work the download. Load in lots of NSLog(s) to track everything. If that works, keep adding your custom code and see if you stumble across an error. I suggest basic NSURLConnection code:

-(void)startDownloading:(NSString *)URLaddress{
NSLog(@"start downloading from: %@",URLaddress);
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:[URLaddress stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]]
                                          cachePolicy:NSURLRequestUseProtocolCachePolicy
                                      timeoutInterval:60.0];
__unused NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(@"didReceiveResponse: %@", response);
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSLog(@"didReceiveData");
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(@"Connection failed! Error - %@ %@",[error localizedDescription], [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(@"connectionDidFinishLoading");
}

Upvotes: 0

Sung-Pil Lim
Sung-Pil Lim

Reputation: 423

I tried your codes.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
  [self.downloadedData appendData:data];
  NSLog(@"%d", data.length);
}
2013-05-04 01:51:13.811 SomethingTodo[2732:c07] 1124
2013-05-04 01:51:13.856 SomethingTodo[2732:c07] 1448
2013-05-04 01:51:14.075 SomethingTodo[2732:c07] 1448
2013-05-04 01:51:17.180 SomethingTodo[2732:c07] 1448
2013-05-04 01:51:17.295 SomethingTodo[2732:c07] 1448

It's working... on ViewController

'request timeout error' was brought to network connection. or...

Are you resuing UITableViewCell? If you initialize for cell reuse codes deal with connection. maybe bring to trouble. Just i thought.

If you attach more your codes. Could I help you more then this.

Upvotes: 2

Shams Ahmed
Shams Ahmed

Reputation: 4513

double check your url address conforms to RFC 2396. so it must include HTTP://

Upvotes: -1

Related Questions