NSURLSession make sure the download is complete

What is the best approach to keep the download working?

I need to upload images to the server and make sure the upload works. If for some reason the download does not work, I will have to try again later.

I am currently using NSUrlSession to upload an image:

- (void)didCreateSignature:(UIImage *)image {

    BLog();

    NSArray   *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString  *documentsDirectory = [paths objectAtIndex:0];
    NSString  *imageFile = [NSString stringWithFormat:@"%@/%@", documentsDirectory,@"test.png"];


    NSData *imageData = UIImagePNGRepresentation(image);
    [imageData writeToFile:imageFile atomically:YES];

    while (![[NSFileManager defaultManager] fileExistsAtPath:imageFile]) {
        [NSThread sleepForTimeInterval:.5];
    }


    NSURLSession *session = [self backgroundSession];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.uploadUrl]];
    [request setHTTPMethod:@"POST"];
    [request addValue:@"image/png" forHTTPHeaderField:@"Content-Type"];

    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:[NSURL fileURLWithPath:signatureFile]];

    [uploadTask resume];

}

Now suppose that the user does not have an Internet connection, then the delegate will be launched:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    BLog();

    if (error == nil)
    {
        NSLog(@"Task: %@ completed successfully", task);
    }
    else
    {
        NSLog(@"Task: %@ completed with error: %@", [task originalRequest], [error localizedDescription]);


        dispatch_async(dispatch_get_main_queue(), ^{
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
            self.internetReachability = [Reachability reachabilityForInternetConnection];
            [self.internetReachability startNotifier];
        });


    }

}

According to Apple's documentation, you should try again later if the Reachability status has changed. So I was thinking of adding these tasks to Array and starting each task again after the Internet connection became available.

Is this the right approach?

, ( TaskManager). , ?

+2
1

, UploadManager Core Data , : ( . - , , )

@implementation UploadManager

- (void) uploadImage:(UIImage *)image toUrl:(NSString *)uploadUrl insertIntoDB:(BOOL)insertIntoDB

{
    if(insertIntoDB) {
        [self insertUploadTaskIntoDBWithImage:image andUploadUrl:uploadUrl];
    }


    // Background upload only works with files
    NSString *fileName = [NSString stringWithFormat:@"%@%@", [uploadUrl sha256], @".png"];
    NSString *signatureFile = [NSString stringWithFormat:@"%@/%@",  NSTemporaryDirectory(), fileName];

    NSData *imageData = UIImagePNGRepresentation(image);
    [imageData writeToFile:signatureFile atomically:YES];

    while (![[NSFileManager defaultManager] fileExistsAtPath:signatureFile]) {
        [NSThread sleepForTimeInterval:.5];
    }

    NSURLSession *session = [self backgroundSession];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:uploadUrl]];
    [request setHTTPMethod:@"POST"];
    [request addValue:@"image/png" forHTTPHeaderField:@"Content-Type"];

    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:[NSURL fileURLWithPath:signatureFile]];

    [self showNetworkActivity:YES];

    self.taskCount++;
    [uploadTask resume];
}


-(void) uploadTasksInDatabase
{
    NSArray* uploadTasks = [self getAllUploadTasksFromDatabase];

    for(UploadTask *task in uploadTasks) {
        UIImage *image = [UIImage imageWithData:task.signature];
        [self uploadImage:image toUrl:task.uploadUrl insertIntoDB:NO];
    }
}


/*
 If an application has received an 
 application:handleEventsForBackgroundURLSession:completionHandler: message, the session
 delegate will receive this message to indicate that all messages previously enqueued for this
 session have been delivered. At this time it is safe to invoke the previously stored completion
 handler, or to begin any internal updates that will result in invoking the completion handler.
 */
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    if (appDelegate.backgroundSessionCompletionHandler) {
        void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
        appDelegate.backgroundSessionCompletionHandler = nil;
        completionHandler();
    }

    self.taskCount = 0;
    NSDebug(@"All tasks are finished");

    [self clearDatabase];

}



- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    BLog();


    self.taskCount--;
    [[NSNotificationCenter defaultCenter] postNotificationName:[task.originalRequest.URL description] object:self];

    if(self.taskCount == 0) {
        [self showNetworkActivity:NO];
    }


    if (error == nil)
    {
        NSLog(@"Task: %@ completed successfully", [task.originalRequest.URL description]);
        [self deleteUploadTaskWithUploadUrl:[task.originalRequest.URL description]];
    }
    else
    {
        NSLog(@"Task: %@ completed with error: %@", [task.originalRequest.URL description], [error localizedDescription]);

    }

}

:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Try to reupload all tasks in DB
    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(backgroundQueue, ^{
            [self.uploadManager uploadTasksInDatabase];
    });


    return YES;
}

, , .

+2

All Articles