Search code examples
iosobjective-cdropboxdropbox-apinsinputstream

NSInputStream with url coming up nil in iOS


I'm trying to set up a NSInputStream, but my input stream is comes out as nil when I step into the code. The url comes from a Dropbox account.

Getting the file through NSData after I have the url through Dropbox Chooser crashes my iPhone 4 (although not when it is running through XCode). The files are just too big, so I wanted to try NSInputStream.

I saw from I cannot initialize a NSInputStream that the url is supposed to be local. Any idea how to stream a file from Dropbox?

Thanks.

- (void)setUpStreamForFile {
// iStream is NSInputStream instance variable already declared
iStream = [NSInputStream inputStreamWithURL:url];
[iStream setDelegate:self];
[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
                   forMode:NSDefaultRunLoopMode];
[iStream open];
}

Solution

  • so thanks to rmaddy's suggestion, I looked up NSURLConnection but decided to use the features of NSURLSession instead.

    I used the NSURLSessionDownloadTask like this. Familiarity with the Dropbox chooser should help.

    -(IBAction)didPressChooser:(id)sender {
    {
        [[DBChooser defaultChooser] openChooserForLinkType:DBChooserLinkTypeDirect
                                        fromViewController:self completion:^(NSArray *results)
         {
             if ([results count]) {
    
                 DBChooserResult *_result = results[0];
                 NSString *extension = [_result.name pathExtension];
                 if ([extension isEqualToString:@"m4a"]) {
                     url = _result.link; //url has already been declared elsewhere
                     DBFileName = _result.name; //DPFileName has also been declared. It's a string
    
                     NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
                     NSURLSession *session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
                    NSURLSessionDownloadTask *getFile = [session downloadTaskWithURL:url];
                     [getFile resume];
    
                 }
    
    
                       } else {
                 // User canceled the action
             }
    
    
         }];
    }
    }
    

    Once you have that, you put in another method that works as the completion handler.

    -(void)URLSession:(NSURLSession *)session
     downloadTask:(NSURLSessionDownloadTask *)downloadTask
    didFinishDownloadingToURL:(NSURL *)location {
    
    NSArray       *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); //I put the file in a temporary folder here so it doesn't take up too much room.
    NSString  *documentsDirectory = [paths objectAtIndex:0];
    
    NSString  *filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory, DBFileName];
    NSData *data = [NSData dataWithContentsOfURL:location];
    [data writeToFile:filePath atomically:YES];
    url = [NSURL fileURLWithPath:filePath];  //Yep, I needed to re-assign url for use elsewhere.
    
    //do other stuff with your local file now that you have its url!
    
    }
    

    A bonus is that you get to keep track of the download progress with this awesome feature:

    -(void)URLSession:(NSURLSession *)session
     downloadTask:(NSURLSessionDownloadTask *)downloadTask
     didWriteData:(int64_t)bytesWritten
    totalBytesWritten:(int64_t)totalBytesWritten
    totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
    {
    NSLog(@"%f / %f", (double)totalBytesWritten,
          (double)totalBytesExpectedToWrite);
    }
    

    Anyway, hope someone finds this useful. Works much faster on my iPhone 4 than NSURLSessionDataTask which works in a similar manner.