0

I am trying to make an app that downloads a pdf file from an online server. What I did was I created 3 buttons that has 3 different URLs and save it to the app's sandbox and open it in iBooks.

But it crashes the app and I am having this error saying...

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter' ***

Here's my code: On Button Click:

     if (sender.tag == 1) {
        pdfTag = 1;
        pdfSource1 = @"http://myweb.com/folder/folderagain/file1.pdf";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:pdfSource1]];
        NSURLConnection *conn = [[NSURLConnection alloc] init];
        (void)[conn initWithRequest:request delegate:self];

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
        dispatch_async(queue, ^{
            dataSource1 = [NSData dataWithContentsOfURL:[NSURL URLWithString:pdfSource1]];
            dispatch_sync(dispatch_get_main_queue(), ^{
            });
            pdfSourcePath1 = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"myPDF1.pdf"];
            NSLog(@"PDF path: %@",pdfSourcePath1);
            [dataSource1 writeToFile:pdfSourcePath1 atomically:YES];
        });

    } else if (sender.tag == 2) {
        pdfTag = 2;
        pdfSource2 = @"http://myweb.com/folder/folderagain/file2.pdf";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:pdfSource2]];
        NSURLConnection *conn = [[NSURLConnection alloc] init];
        (void)[conn initWithRequest:request delegate:self];

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
        dispatch_async(queue, ^{
            dataSource2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:pdfSource2]];
            dispatch_sync(dispatch_get_main_queue(), ^{
            });
            pdfSourcePath2 = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"myPDF2.pdf"];
            NSLog(@"PDF path: %@",pdfSourcePath2);
            [dataSource2 writeToFile:pdfSourcePath2 atomically:YES];
        });
    } else if (sender.tag == 3) {
        pdfTag = 3;
        pdfSource3 = @"http://myweb.com/folder/folderagain/file3.pdf";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:pdfSource3]];
        NSURLConnection *conn = [[NSURLConnection alloc] init];
        (void)[conn initWithRequest:request delegate:self];

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
        dispatch_async(queue, ^{
            dataSource3 = [NSData dataWithContentsOfURL:[NSURL URLWithString:pdfSource3]];
            dispatch_sync(dispatch_get_main_queue(), ^{
            });
            pdfSourcePath3 = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"myPDF3.pdf"];
            NSLog(@"PDF path: %@",pdfSourcePath3);
            [dataSource3 writeToFile:pdfSourcePath3 atomically:YES];
        });
    }

For opening the file:

     if (pdfTag == 1) {
     NSURL *url = [NSURL fileURLWithPath:pdfSourcePath1];
     docController1 = [UIDocumentInteractionController interactionControllerWithURL:url];

     docController1.delegate = self;

     [docController1 presentOpenInMenuFromRect:btn1.frame inView:self.view animated:YES];
    } else if (pdfTag == 2) {
        NSURL *url = [NSURL fileURLWithPath:pdfSourcePath2];
        docController2 = [UIDocumentInteractionController interactionControllerWithURL:url];

        docController2.delegate = self;

        [docController2 presentOpenInMenuFromRect:btn2.frame inView:self.view animated:YES];
    } else if (pdfTag == 3) {
        NSURL *url = [NSURL fileURLWithPath:pdfSourcePath3];
        docController2 = [UIDocumentInteractionController interactionControllerWithURL:url];

        docController2.delegate = self;

        [docController2 presentOpenInMenuFromRect:btn3.frame inView:self.view animated:YES];
    }

I hope I could find answer.

Lakan Bahande
  • 165
  • 1
  • 3
  • 12
  • According to me `pdfSourcePath1, pdfSourcePath2, pdfSourcePath3` are `nil`. Open file method is getting called before the pdf source path are set inside block code. Try placing debug points. – Deepesh Gairola May 17 '13 at 04:51
  • Does the error occur on trying to open the file or on download? Can you log the pdfSourcePath1,2,3 before you build the NSURL for opening. Finally, your use of GCD directly to do the requests is strange and tough to read. Look up NSURLConnection sendAsynchronousRequest:.... – danh May 17 '13 at 04:53
  • @Deepesh my code for opening file is inside connectionDidFinishLoading:(NSURLConnection *)connection – Lakan Bahande May 17 '13 at 05:53
  • @danh the error occurs after the download, it should first present a popover that I will open the file in another app (which is iBooks) but it crashes. – Lakan Bahande May 17 '13 at 05:55

3 Answers3

0

In your code i could not able to see the API initFileURLWithPath you used anywhere..

Just below is my suggestion for your task,

The below is the code to get the remote Pdf as a NSData using the server file path and store in application sandbox.

     NSData *pdfData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:bookUrlString]];
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
     NSString *documentsDirectory = [paths objectAtIndex:0];
     NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"myPDF.pdf"];
     [pdfData writeToFile:filePath atomically:YES

As per my understanding for this purpose, this doesn't require any NSURLRequest or NSURLConnection...

Easwaramoorthy Kanagaraj
  • 3,925
  • 8
  • 36
  • 62
  • The code is using both NSURLRequest and NSURLConnection indirectly by using initWithContentsOfURL (which is probably ill-advised). If the OP intends to release the app, an asynch request should almost certainly be used to fetch a pdf from a web service. – danh May 17 '13 at 18:52
0

Networking is a complex task, I will never suggest you to download or upload a file using the -initWithURL method, since is not asynchronous and will block the main thread. You should go with NSURLConnection class and its delegate methods, or the amazing class method that accept just a queue and a completion block.
You are doing weird stuff you use NSURLConnection but you use a ..WithURL method, you should go with one one them.
There are different download managers on the web that could help you in whole process, since they wrap the NSURLConnection class and delegate methods.
There is:

  1. AFNetworking link
  2. MKNetworking (my favorite)link
Andrea
  • 26,120
  • 10
  • 85
  • 131
0

NSData dataWithContentsOfURL works well as long as the size of the file is small.

I won't suggest you to download large file using this method, instead use NSURLConnection or AFNetworking.

How to use NSURLConnection and AFNetworking to download a file are explained in the following answer: https://stackoverflow.com/a/16454923/2548707

Community
  • 1
  • 1
SahilS
  • 396
  • 5
  • 7
  • `dataWithContentsOfURL:` should _never_ be used for retrieving information across the network, regardless of the amount. It blocks the thread; any network problems have a high chance of stalling your application. – jscs Jul 04 '13 at 02:59
  • @JoshCaswell that's true. – SahilS Jul 30 '13 at 20:22