Does Facebook class of iPhone Facebook SDK have ca

2019-02-09 04:45发布

Is there anyway to cancel a Facebook object's pending request?

I can't find any methods in Facebook.h, or a way to access the underlying NSURLConnection object. If I press back on the navigation bar and the their is a pending asynchronous Facebook request, the request tries to send a message to a deallocated view once the response has come, causing the application to crash.

2条回答
Summer. ? 凉城
2楼-- · 2019-02-09 05:12

EDIT As pointed out in Tim's answer to this question, this information is now obsolete with the newest releases of the Facebook iOS SDK.

There is no way to cancel a pending request. However, this shouldn't be crashing your app.

The Facebook class uses the FBRequest class under the hood to make all of its REST or Graph API requests, and this is the class that ends up with a reference to your view (controller?) as its delegate property. Looking at the header for FBRequest:

@interface FBRequest : NSObject {
  id<FBRequestDelegate> _delegate;
  NSString*             _url;
  NSString*             _httpMethod;
  NSMutableDictionary*  _params;
  NSURLConnection*      _connection;
  NSMutableData*        _responseText;
}

@property(nonatomic,assign) id<FBRequestDelegate> delegate;

The assign attribute in the property declaration makes it seem that it stores a weak-ref to your class, but then in FBRequest.m:

+ (FBRequest *)getRequestWithParams:(NSMutableDictionary *) params
                         httpMethod:(NSString *) httpMethod
                           delegate:(id<FBRequestDelegate>) delegate
                         requestURL:(NSString *) url {
  FBRequest* request    = [[[FBRequest alloc] init] autorelease];
  request.delegate      = [delegate retain]; // <- It's retained! (Comment mine)
  request.url           = [url retain];
  request.httpMethod    = [httpMethod retain];
  request.params        = [params retain];
  request.connection    = nil;
  request.responseText  = nil;

  return request;
}

It clearly retains the delegate. So, in the normal flow of your application, when you think your view controller should be deallocated after being popped off the navigation stack, the FBRequest has ensured that it will still be alive to receive the response by taking ownership of it.

This makes it seem like you might have other memory management issues elsewhere in the app.

查看更多
够拽才男人
3楼-- · 2019-02-09 05:20

For anyone who comes across this question, it appears that Matt's observation does not apply to the newest facebook-iphone-sdk. The parameters are no longer explicitly retained in the relevant method:

+ (FBRequest *)getRequestWithParams:(NSMutableDictionary *) params
                         httpMethod:(NSString *) httpMethod
                           delegate:(id<FBRequestDelegate>) delegate
                         requestURL:(NSString *) url {

  FBRequest* request = [[[FBRequest alloc] init] autorelease];
  request.delegate = delegate;
  request.url = url;
  request.httpMethod = httpMethod;
  request.params = params;
  request.connection = nil;
  request.responseText = nil;

So memory management for the delegate falls back to the property declaration in the .h file:

@property(nonatomic,assign) id<FBRequestDelegate> delegate;

This means a crash is now possible since the delegate object can be deallocated before the FBRequest is completed.

Update:

A possible workaround is suggested in this question to allow cancellation of pending FBRequests.

Update 2:

To avoid a crash in the case where the delegate gets deallocated before the FBRequest finishes, you need to cancel the active FBRequest's connection as you deallocate the delegate (which is basically what Matt suggests in the linked question). However (I'm not sure if this is new), you can do this directly to the FBRequest since it exposes it's NSURLConnection property. So, if you retain your FBRequest object in a property:

@property (nonatomic, retain) FBRequest *myRequest;

and save the request object when you make your call:

self.myRequest = [facebookObj requestWithGraphPath:@"me" andDelegate:self];

you can clean everything up in your dealloc:

- (void)dealloc
{
 if( myRequest ) {
    [[myRequest connection] cancel];
    [[myRequest release];
  }

  ...

  [super dealloc];
}

Obviously, you should probably also release and nil the FBRequest property in the delegate methods once you have processed the response.

查看更多
登录 后发表回答