我偶尔需要取消 FaceBook 图形请求,但他们的 API 中似乎没有取消或类似的方法可以这样做。目前,由于我分配给请求的委托已被释放,有时会发生崩溃。提交后有什么方法可以取消图形请求?
9 回答
我假设您正在谈论 facebook-ios-sdk 项目,以及 Facebook.h 中缺少取消方法。我也注意到了这一点,最终决定添加我自己的取消方法。请注意,您分配给请求的委托不应该被释放然后引用,因为请求保留了委托。看到这个类似的问题。现在,如果您发现自己出于其他原因确实需要取消方法...
添加取消方法:
Facebook 请求以不透明的方式发出。Facebook
你永远不会看到他们,只能通过课堂听到结果。在后台,Facebook
该类使用(不供公共使用)FBRequest
类发出 Graph API 请求。这个类基本上是一个花哨的NSURLConnection
代表。因此,要取消请求,NSURLConnection
只需告知会员即可cancel
。将此方法添加到 FBRequest:
// Add to FBRequest.h
- (void)cancel;
和...
// Add to FBRequest.m
- (void)cancel {
[_connection cancel];
[_connection release], _connection = nil;
}
现在,要在 Facebook 类中公开一个接口以利用新方法......
// Add to Facebook.h
- (void)cancelPendingRequest;
和...
// Add to Facebook.m
- (void)cancelPendingRequest {
[_request cancel];
[_request release], _request = nil;
}
这里的所有都是它的。上面的方法将取消最近的请求,您将永远不会再收到它的消息。
我遵循了此处列出的 Matt Wilding 的方法,这非常有用,感谢 Matt。不幸的是,它对我来说不太管用,所以我做了一些调整,现在它可以工作了......而且这种修改后的方法也远离了核心 facebook 类......
//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];
}
更新于 2012 年 4 月 22 日
我用最新的 Facebook iOS SDK 更新了 Matt 的版本。我的项目正在使用 ARC,但我包含了非 ARC Facebook 资源,以便我可以修改代码。(当然,我们需要为 Facebook 源文件设置“-fno-objc-arc”标志)。棘手的部分是防止内存泄漏,我认为我做得对。但是当我在仪器中测试它时,我仍然看到非常少量的内存泄漏。幸运的是,细节表明它们与这些代码无关,所以我只是假设它们与应用程序资源处理有关。
这是我实现的代码:
// Add to Facebook.h
- (void)cancelPendingRequest:(FBRequest *)releasingRequest;
和...
// Add to Facebook.m
- (void)cancelPendingRequest:(FBRequest *) releasingRequest{
[releasingRequest.connection cancel];
[releasingRequest removeObserver:self forKeyPath:requestFinishedKeyPath];
[_requests removeObject:releasingRequest];
}
在您使用 FBRequestDelegate 的项目中
// Declare this member or property to the .h file
FBRequest * currentFbRequest;
// Declare this method
-(void)cancelFBRequest;
和 ...
// 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;
对于我们这些构建静态库但无法访问实现文件的人来说,类别将是最好的选择。
对于我们这些没有构建静态库的人来说,使用类别也是最佳选择,因为您不需要修改现有文件。
这里是所说的类别。
// Facebook+Cancel.h
#import "Facebook.h"
@interface Facebook (Facebook_cancel)
- (void)cancelPendingRequest:(FBRequest *)releasingRequest;
- (void)cancelAllRequests;
@end
然后是 .m 文件
// 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
对于那些使用任何其他答案的人,您正在导致内存泄漏。Facebook SDK 将通过 NSLog 警告您尚未删除观察者。cancelAllRequests 方法中的第四行修复了这个问题。
从 SDK 3.1 开始,这很容易,因为startWithCompletionHandler:返回一个FBRequestConnection对象,它有一个-(void)cancel;
方法。
例如:
// 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];
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];
}
在FBRequest.h
中,我不得不这样做,add _delegate = nil;
因为在我的情况下,请求委托不再存在(它已被解雇),这导致了崩溃。
每当我导航到另一个视图时,我都会在 2012 年 8 月有效的之前的 iOS Facebook SDK 崩溃。我的解决方案基于@staticfiction 响应:
在 .h 中添加BOOL viewWillDisappear
了标志。在-(void) viewWillDisappear:
将标志设置为YES。将标志重置为 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];
}
}
对此 URL 进行 CURL 调用
https://graph.facebook.com/REQUEST_ID?method=delete