Facebook API - How to cancel Graph Request

ぃ、小莉子 提交于 2019-12-18 03:38:17

问题


I occasionally need to cancel a FaceBook graph request, but there seems to be no cancel or similar method in their API to do so. At the moment, crashes sometimes occur as the delegate I assigned to the request has been deallocated. Is there any way to cancel a graph request once submitted please?


回答1:


I'm assuming you're talking about the facebook-ios-sdk project, and the lack of a cancel method in Facebook.h. I noticed this as well, and eventually decided to add my own cancel method. Just to note, the delegate you assign to the request shouldn't ever be dealloc'd and then referenced, because the request retains the delegate. See this similar question. Now, if you find yourself really needing a cancel method for some other reason...

Adding a cancel method:
Facebook requests are made in an opaque manner. You never see them, and only hear about results via the Facebook class. Under the hood, the Facebook class makes Graph API requests with the (not for public use) FBRequest class. This class is is basically a fancy NSURLConnection delegate. So to cancel the request, the member NSURLConnection just has to be told to cancel. Adding this method to FBRequest:

// Add to FBRequest.h
- (void)cancel;

And...

// Add to FBRequest.m
- (void)cancel {
    [_connection cancel];
    [_connection release], _connection = nil;
}

Now, to expose an interface in the Facebook class to make use of the new method...

// Add to Facebook.h
- (void)cancelPendingRequest;  

And...

// Add to Facebook.m
- (void)cancelPendingRequest {
    [_request cancel];
    [_request release], _request = nil;
}

That's all there is to it. The method above will cancel the most recent request, and you'll never hear from it again.




回答2:


I've followed Matt Wilding's approach listed here, which was very useful, thanks Matt. Unfortunately it didnt quite work for me, so I made some tweaks and now it works... also this revised approach keeps out of the core facebook classes...

//in .h define an FBRequest property
@property (nonatomic, retain) FBRequest * pendingFBRequest;

//in .m when making your request, store it in your FBRequest property
pendingFBRequest = [facebook requestWithGraphPath:@"me/feed"
                                        andParams:params
                                    andHttpMethod:@"POST"
                                      andDelegate:self];

//create a timer for your timeout
pendingFacebookActionTimer = [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(onPendingFacebookActionTimeout) userInfo:nil repeats:NO];

//cancel the action on the timeout's selector method
-(void)onPendingFacebookActionTimeout {

    [pendingFBRequest.connection cancel];

}



回答3:


Updated on 22/April/2012

I update Matt's version with the most up-to-date Facebook iOS SDK. My Project is using ARC, but I include the non-ARC Facebook sources so that I can modify the codes. (Of Course, we need to set the "-fno-objc-arc" flag for Facebook source files). The tricky part is to prevent the memory leak, and I think I am doing it correctly. But When I test it in the instrument, I still see very small amount of memory leak. Fortunately, the details show that they are not related to these codes, so I just assume they are related to the app resource handling.

Here is the code I implemented:

// Add to Facebook.h
- (void)cancelPendingRequest:(FBRequest *)releasingRequest; 

And...

// Add to Facebook.m
- (void)cancelPendingRequest:(FBRequest *) releasingRequest{
    [releasingRequest.connection cancel];
    [releasingRequest removeObserver:self forKeyPath:requestFinishedKeyPath];
    [_requests removeObject:releasingRequest];    
}

And in your project which uses FBRequestDelegate

// Declare this member or property to the .h file
FBRequest * currentFbRequest;

// Declare this method
-(void)cancelFBRequest;

And ...

// In .m file
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// prepare your necessary request data and parameter ...
currentFbRequest = [appDelegate.facebook requestWithGraphPath:@"/me/photos" 
    andParams:params 
    andHttpMethod:@"POST" 
    andDelegate:self];



// Then in the method where you want to cancel
AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.facebook cancelPendingRequest:currentFbRequest];
currentFbRequest=nil;



回答4:


For those of us who build the static library and are unable to access the implementation files, a category would be the best way to go.

For those of us who did not build the static library, using a category would be optimal as well because you don't need to modify the existing files.

Here is said category.

// Facebook+Cancel.h
#import "Facebook.h"

@interface Facebook (Facebook_cancel)

- (void)cancelPendingRequest:(FBRequest *)releasingRequest;

- (void)cancelAllRequests;

@end

And then the .m file

// Facebook+Cancel.m
#import "Facebook+Facebook_cancel.h"

@implementation Facebook (Facebook_cancel)

- (void)cancelPendingRequest:(FBRequest *)releasingRequest{
    [releasingRequest.connection cancel];
    if ([_requests containsObject:releasingRequest]) {
        [_requests removeObject:releasingRequest];
        [releasingRequest removeObserver:self forKeyPath:@"state"];

    }
}

- (void)cancelAllRequests {
    for (FBRequest *req in [_requests mutableCopy]) {
        [_requests removeObject:req];
        [req.connection cancel];
        [req removeObserver:self forKeyPath:@"state"];
    }
}

@end

For those using any other answer, you are causing a memory leak. The Facebook SDK will warn you through NSLog that you have not removed an observer. The fourth line in the cancelAllRequests method fixes this problem.




回答5:


Try this instead of using NSTimer:

FBRequest *fbRequest = [facebook requestWithGraphPath:@"me" andDelegate:self];
[self performSelector:@selector(fbRequestTimeout:) withObject:fbRequest afterDelay:30];

- (void)fbRequestTimeout:(FBRequest *)fbRequest
{
    [fbRequest.connection cancel];
    [fbRequest setDelegate:nil];
}



回答6:


Since SDK 3.1, it's very easy, as startWithCompletionHandler: returns a FBRequestConnection object, which has a -(void)cancel; method.

For example:

// In interface or .h definitions:
@property (strong, nonatomic) FBRequest             *fBRequest;
@property (strong, nonatomic) FBRequestConnection   *fbConnection;

// when needed in class (params should be set elsewhere, this is just an example):
self.fBRequest = [[FBRequest alloc] initWithSession:[FBSession activeSession] graphPath:@"me/photos" parameters:params HTTPMethod:@"POST"];
self.fbConnection = [self.fBRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error){
    NSLog(@"Publish complete, error: %d", error.code);
}];

// now, to cancel anywhere in the class, just call:
[self.fbConnection cancel];



回答7:


In FBRequest.h, I've had to add _delegate = nil; because in my case, the request delegate no longer existed (it was dismissed) which caused a crash.




回答8:


I was having a crash with the previous iOS Facebook SDK which was valid in August 2012 whenever I navigated to another view. My solution is based on @staticfiction response:

Added BOOL viewWillDisappear flag in .h. In -(void) viewWillDisappear: set the flag to YES. Reset flag to NO in -(void) viewDidAppear:

//in .h define an FBRequest property
@property (nonatomic, retain) FBRequest * pendingFBRequest;


 /*
 * Graph API: Search query to get nearby location.
 */
- (void)apiGraphSearchPlace:(CLLocation *)location {

    currentAPICall = kAPIGraphSearchPlace;
    NSString *centerLocation = [[NSString alloc] initWithFormat:@"%f,%f",
                                location.coordinate.latitude,
                                location.coordinate.longitude];
    JMYAppDelegate *delegate = (JMYAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   @"place",  @"type",
                                   centerLocation, @"center",
                                   @"1000",  @"distance",
                                   nil];
    [centerLocation release];
    pendingFBRequest = [[delegate facebook] requestWithGraphPath:@"search" andParams:params andDelegate:self];

    if (viewWillDisappear) {
        [pendingFBRequest.connection cancel];
        [pendingFBRequest setDelegate:nil];
        [self hideActivityIndicator];
    }
}



回答9:


Make a CURL call to this URL

https://graph.facebook.com/REQUEST_ID?method=delete


来源:https://stackoverflow.com/questions/4958912/facebook-api-how-to-cancel-graph-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!