Alec Kriebel
Alec Kriebel

Reputation: 192

Stopping Asynchronous Block Request when Leaving View (AFNetworking; iOS)

I am using AFNetworking (2.3.1) to parse JSON data and display it in labels.

To do this, I am using setCompletionBlockWithSuccess which is declared in AFHTTPRequestOperation.h.

Three functions like this are being called on viewDidLoad, one looks like:

-(void)parse {

    NSURL *url = [[NSURL alloc] initWithString:kURL];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    operation.responseSerializer = [AFJSONResponseSerializer serializer];

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

        NSLog(@"Parse Successful");
        //Code for JSON Parameters and to display data


    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

        NSLog(@"%@", [error localizedDescription]);
        //Code for Failure Handling

    }];

    [operation start];

}

While this works like a charm, because it is being contained in a block request, this process continues throughout the application state. So when this data does not need to be displayed, the requests are still loading, and I am receiving memory warnings because of these blocks.

My question is, how can I stop, cancel, or pause these processes once I leave the View Controller that they are created on in order to save memory and data, or handle them appropriately?

Forgive me if this is an obvious answer, and I am just handling or creating blocks in a totally wrong way. I am new to both AFNetworking and Blocks, operations, async requests, and the like.

Thanks.

Upvotes: 0

Views: 2354

Answers (2)

Alec Kriebel
Alec Kriebel

Reputation: 192

As it turns out, the lack of stopping was stemming from a timer (that called the block request, or the function parse) that was not invalidated once the view disappears. Invalidating the timer on -(void)viewDidDisappear: fixed the problem.

Upvotes: 1

Brandon
Brandon

Reputation: 2427

Assuming you have an AFHTTPRequestOperation object called operation:

[operation cancel];

This probably belongs in ViewWillDisappear.

And then inside your failure block (which will then be called) you can check to see if it failed because of an error or if you canceled it:

if ([operation isCancelled])
{
     //I canceled it.
}

Update - a more concrete example of how to save a reference to the operation and cancel it when the view dissapears.

@interface myViewController ()

@property (strong, nonatomic) AFHTTPRequestOperation *parseOperation;

@end

@implementation myViewController

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

//no need to check to see if the operation is nil (because it never happened or it's complete) because
//messages sent to nil are ok.
[self.parseOperation cancel];
}

-(void)parse {

NSURL *url = [[NSURL alloc] initWithString:kURL];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];

//save the parse operation so we can cancel it later on if we need to
self.parseOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
self.parseOperation.responseSerializer = [AFJSONResponseSerializer serializer];

__weak myViewController *weakSelf = self;
[self.parseOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    //nil out the operation we saved earlier because now that it's finished we don't need to cancel it anymore
    weakSelf.parseOperation = nil;

    NSLog(@"Parse Successful");
    //Code for JSON Parameters and to display data


} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    if (!operation.isCancelled) {
    NSLog(@"%@", [error localizedDescription]);
    //Code for Failure Handling
    }
}];

[self.parseOperation start];
}

Upvotes: 1

Related Questions