Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

AFNetworking + queue + cancel operations + junk files #657

Closed
zaabalonso opened this Issue · 7 comments

4 participants

Filippos Zampounis Mattt Thompson Daniel Tull Pete
Filippos Zampounis

i 'm downloading some files using AFNetworking using a queue. Here is my code:

      apiClient =[[AFHTTPClient alloc]initWithBaseURL: [NSURL URLWithString:ZFREMOTEHOST]];
for (NSString *element in self.productsArray) {
        NSURL *url = [NSURL URLWithString:element];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        op = [[AFHTTPRequestOperation alloc] initWithRequest:request];

        NSString *documentsDirectory = nil;
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        documentsDirectory = [paths objectAtIndex:0];

        NSString *targetFilename = [url lastPathComponent];
        NSString *targetPath = [documentsDirectory stringByAppendingPathComponent:targetFilename];

        op.outputStream = [NSOutputStream outputStreamToFileAtPath:targetPath append:NO];

        [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            //failure case
            NSLog(@"BaaZ  File NOT Saved %@", targetPath);

            //remove the file if saved a part of it!
            NSFileManager *fileManager = [NSFileManager defaultManager];
            [fileManager removeItemAtPath:targetPath error:&error];

            if (error) {
                NSLog(@"error dude");
            }

            if ([operation isCancelled]) {
                //that doesn't work.
                NSLog(@"Canceled");
            }
        }];

        [op setDownloadProgressBlock:^(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
            if (totalBytesExpectedToRead > 0) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    self.progressView.alpha = 1;
                    self.progressView.progress = (float)totalBytesRead / (float)totalBytesExpectedToRead;
                    NSString *label = [NSString stringWithFormat:@"Downloaded %lld of %lld bytes", totalBytesRead,totalBytesExpectedToRead];
                    self.progressLabel.text = label;
                });
            }
        }];
    [self.resourcesArray addObject:op];

    }
for (AFHTTPRequestOperation *zabols in self.resourcesArray) {
    [apiClient.operationQueue addOperation:zabols];
}

the code is working fine on file downloading but i want some cancel functionality so i have a button with an action that has the code below:

[apiClient.operationQueue cancelAllOperations];

the operations cancel file but then there are some junk files on the Documents folder. By saying junk i mean file that started downloading i canceled them and the i get a file with the same name but useless can't be opened cause it's damaged.

How can i prevent AF from doing that and keep only the completed files when i cancel it?

any help would be grateful.

Also tried canceling job by job like that:

for (AFHTTPRequestOperation *ap in apiClient.operationQueue.operations) {
        [ap cancel];
        NSLog(@"%@",ap.responseFilePath);
        NSFileManager *fileManager = [NSFileManager defaultManager];
        [fileManager removeItemAtPath:ap.responseFilePath error:nil];

    }

and deleting the junk files but that doesn't work either.

MY THOUGHTS :

THERE SHOULD BE SOME KIND OF TEMP_FILES FOLDER AND ON_COMPLETE ACTION MOVE THEM IN THE ACTUAL FILE PATH ELSE DELETE THEM(WE DON"T NEED SEMI DOWNLOADED FILES).

SO i GUESS the problem is here : op.outputStream = [NSOutputStream outputStreamToFileAtPath:targetPath append:NO];

and the way AF manages its downloaded files.

Mattt Thompson
Owner

completionBlock is run whether the operation finishes or was cancelled. If you need specific logic to clean up temp files when cancelled, you can configure that yourself. Otherwise, I'm very happy with the current behavior of AFNetworking.

Mattt Thompson mattt closed this
Filippos Zampounis

no matt i don't get in completionBlock on cancel just when full downloaded. On cancel it doesn't get in completionBlock or failedBlock

Mattt Thompson
Owner

I would encourage you to read the AFNetworking documentation more closely, as well as the Apple documentation for NSOperation. This behavior is clearly explained between those two sources.

Daniel Tull

While the completionBlock on the operation is called, the blocks given to setCompletionBlockWithSuccess:failure: do not, which is what @zaabalonso is enquiring about.

From the source of AFHTTPRequestOperation, AFImageRequestOperation, AFPropertyListRequestOperation, AFJSONRequestOperation and AFXMLRequestOperation you can see the block is just returning if the operation is cancelled.

It seems to me there is no obvious (blocky) way to know when an AFNetworking operation is cancelled.

Pete

Just to add to @danielctull's comment, for operations created via AFHTTPClient's getPath:parameters:success:failure: the operation isn't returned or exposed in anyway. I don't believe, therefore, that there's a way for the caller to set a completion block to handle the request being cancelled.

I had also (wrongly it seems) assumed that the failure block would be called if the request was cancelled.

Daniel Tull danielctull referenced this issue from a commit in danielctull/AFNetworking
Daniel Tull danielctull Cause a failure when an operation is cancelled, fixes #657 7134e96
Mattt Thompson
Owner

@zaabalonso @PeteC To be clear: completionBlock is a property of NSOperation. getPath: and other convenience methods use setCompletionBlockWithSuccess:failure:, which returns early if the operation was cancelled. Cancelled operations are not failing operations by AFNetworking, and if you need to define behavior to execute when the operation is cancelled, do setCompletionBlock: directly yourself.

Pete

Thanks for getting back on this @mattt . I fully understand completionBlock is a property of NSOperation.

I often have code that depends on an operation to complete, whether successfully or not. For example I may have dispatch groups waiting on operations. This is why I feel there should be some feedback when an operation is cancelled. While I could write my own completion blocks to handle this, they'd look very similar to AFNetworking's current implementation.

In a quick straw poll of developers at a London developer group meeting, everyone assumed the failure block would be called if an operation was cancelled. And I was very careful how the question was asked :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.