Using iOS Dropbox SDK to do a Chunked Upload of Core Data

I have an iOS app that uses Core Data for persistent data storage. I integrated Dropbox as a way for users to perform a a backup of the persistent store file (appname.sqlite).

A UIButton calls a method to see if a file already exists on Dropbox:

  • iOS Share Extension is not working in Chrome
  • Where to store global constants in an iOS application?
  • How can I detect the dismissal of a modal view controller in the parent view controller?
  • XMLRPC-iOS for iOS project
  • Linking child view controllers to a parent view controller within storyboard
  • Get List Available Wireless Access Points
  •             if([[DBSession sharedSession]isLinked])
                {
                   NSString *folderName = [[self.dateFormatter stringFromDate:[NSDate date]] stringByReplacingOccurrencesOfString:@"/" withString:@"-"];
                   NSString *destinationPath = [NSString stringWithFormat:@"/GradeBook Pro/Backup/%@/",folderName];
                   self.metadataIndex = METADATA_REQUEST_BACKUP;
                   [self.restClient loadMetadata:destinationPath];
                }
    

    The loadedMetadata delegate method initiates the upload with the rev number of the existing file (if one exists).

    -(void) restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata
    {
                SAVE_CORE_DATA;
                NSString *folderName = [[self.dateFormatter stringFromDate:[NSDate date]] stringByReplacingOccurrencesOfString:@"/" withString:@"-"];
                NSString *documentsDirectory = DOCUMENTS_DIRECTORY;
                NSString *sourcePath = [NSString stringWithFormat:@"%@/GradeBookPro.sqlite", documentsDirectory];
                NSString *destinationPath = [NSString stringWithFormat:@"/GradeBook Pro/Backup/%@/",folderName];
                [self.restClient uploadFile:@"GradeBookPro.sqlite" toPath:destinationPath withParentRev:[[metadata.contents lastObject]rev] fromPath:sourcePath];               
    }
    

    This works well for reasonably small files or large files over a perfect network connection but any small error during the upload cancels the whole process. I would like to switch to using the chunked upload methods but I’m at a loss as to how to actually do the ‘chunking’ of the .sqlite file.

    I can’t seem to find any sample apps that are using the chunked upload that I can learn from and the documentation simply says to provide the file in chunks.

    So, my questions are:

    1. Is the chunked upload the right approach to addressing the user issues with uploading large files over a possibly spotty network connection?

    2. Can you point me to sample code / app / documentation for ‘chunking’ a file? I’m pretty comfortable with the Dropbox SDK.

    Thanks!

    Solutions Collect From Internet About “Using iOS Dropbox SDK to do a Chunked Upload of Core Data”

    I’m going to answer this myself just in case anyone else has the same issue.

    It turns out that I was making this way more difficult than it needed to be. The Dropbox SDK handles chunking the files so I just needed to initate the transfer and react to the delegate calls. The methods used are:

    To send a file chunk – for the first chunk, use nil for the uploadId and 0 for the offset:

    - (void)uploadFileChunk:(NSString *)uploadId offset:(unsigned long long)offset fromPath:(NSString *)localPath;
    

    After sending the last chunk, use this method to commit the upload:

    - (void)uploadFile:(NSString *)filename toPath:(NSString *)parentFolder withParentRev:(NSString *)parentRev fromUploadId:(NSString *)uploadId;
    

    I handled the delegate method as follows:

        - (void)restClient:(DBRestClient *)client uploadedFileChunk:(NSString *)uploadId newOffset:(unsigned long long)offset fromFile:(NSString *)localPath expires:(NSDate *)expiresDate
        {
            unsigned long long fileSize = [[[NSFileManager defaultManager]attributesOfItemAtPath:[FileHelper localDatabaseFilePath] error:nil]fileSize];
    
            if (offset >= fileSize)
            {
                //Upload complete, commit the file.
                [self.restClient uploadFile:DATABASE_FILENAME toPath:[FileHelper remoteDatabaseDirectory] withParentRev:self.databaseRemoteRevision fromUploadId:uploadId];
            }
            else
            {
                //Send the next chunk and update the progress HUD.
                self.progressHUD.progress = (float)((float)offset / (float)fileSize);
                [self.restClient uploadFileChunk:uploadId offset:offset fromPath:[FileHelper localDatabaseFilePath]];
            }
        }
    

    Since the main problem that I was trying to address was handling poor connections I implemented delegate method for failed chunk uploads:

    - (void)restClient:(DBRestClient *)client uploadFileChunkFailedWithError:(NSError *)error
    {
        if (error != nil && (self.uploadErrorCount < DROPBOX_MAX_UPLOAD_FAILURES))
        {
            self.uploadErrorCount++;
            NSString* uploadId = [error.userInfo objectForKey:@"upload_id"];
            unsigned long long offset = [[error.userInfo objectForKey:@"offset"]unsignedLongLongValue];
            [self.restClient uploadFileChunk:uploadId offset:offset fromPath:[FileHelper localDatabaseFilePath]];
        }
        else
        {
          //show an error message and cancel the process
        }
    }