gpt4 book ai didi

ios - 您如何打开一个 FBSession,其完成处理程序不会在每次 session 状态更改时被保留和调用?

转载 作者:可可西里 更新时间:2023-11-01 03:47:22 24 4
gpt4 key购买 nike

出于某些奇怪的原因,Facebook 决定创建实际上只是通知观察者的完成处理程序。忽略他们这样做的原因,我需要一些方法来发出打开 FBSession 的请求并且只发生一次回调,因为不能保留回调中的对象。

如果用户按下一个按钮,并且具有“publish_actions”权限的 Facebook session 未打开,则应显示一个事件指示器,并在 Facebook session 打开时阻止与 UI 的交互。

这是用于登录 Facebook 的方法:

- (void)loginToFacebookFromViewController:(UIViewController *)viewController completion:(void (^)(NSString *facebookAccountName))completion
{
if([self isLoggedIntoFacebook] == NO)
{
[viewController startLoadingAnimation];

[FBSession openActiveSessionWithPublishPermissions: @[ @"publish_actions" ] defaultAudience:FBSessionDefaultAudienceFriends allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{
if(error == nil)
{
[FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id<FBGraphUser> user, NSError *error)
{
NSString *accountName = [user name];

if(error == nil)
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
[standardUserDefaults setObject:accountName forKey:TSFacebookAccountName];
[standardUserDefaults synchronize];
}

[viewController stopLoadingAnimation];

if(completion != nil)
completion(accountName);
}];
}
else
{
[viewController stopLoadingAnimation];

if(completion != nil)
completion(nil);
}
}];
}
else
{
if(completion != nil)
completion([self facebookAccountName]);
}
}

如果没有保留完成处理程序(同样是出于毫无意义的原因,因为当 session 状态更改时会发布 NSNotifications),那么此方法将完美运行。

因为该应用程序不围绕 Facebook,所以我对 session 状态何时更改不感兴趣。如果用户尝试与 Facebook 分享某些内容并且事件 session 未打开,则登录过程将被启动,如果 session 已打开,共享过程将继续。否则,将向用户显示一条错误消息。

有人能解释一下 Facebook 期望如何实现这种功能吗,因为这似乎是一个非常常见的用例,在有人提到“你为什么不使用默认的 Facebook 对话框”之前,这是因为需要自定义 UI呈现给用户以收集用于 Open Graph 帖子的特定信息。

最佳答案

如果您不像我那样关心从 FBSessionStateHandler 接收状态更改,那么下面的代码应该允许您登录 Facebook 并为您提供一个不保留的完成 block 。

传递到方法中的完成 block 将始终在发生任何状态更改时被使用,然后立即消失,以便在发生另一个状态更改时忽略它。

typedef void(^FacebookLoginCompletionBlock)(id<FBGraphUser> user);

- (void)loginToFacebookFromWithCompletionBlock:(FacebookLoginCompletionBlock)completionBlock
{
// If the user is not logged into Facebook attempt to open a session with "publish_actions" permissions.
if([[FBSession activeSession] isOpen] == NO)
{
// Copy the completion block to a local variable so it can be nil'd out after it is used to prevent retain loops.
__block FacebookLoginCompletionBlock copiedCompletionBlock = completionBlock;

[FBSession openActiveSessionWithPublishPermissions:@[ @"publish_actions" ] defaultAudience:FBSessionDefaultAudienceFriends allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{
// Only attempt to run any of this code if there is a completion block to call back to. If completion block is nil than it has already been used and this is a state change that we do not care about.
if(copiedCompletionBlock != nil)
{
// Because this method is only concerned with the user logging into Facebook just worry about the open state occuring with no errors.
if(status == FBSessionStateOpen && error == nil)
{
// If the user successfully logged into Facebook download their basic profile information so the app can save the information to display to the user what account they are logged in under.
[FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id<FBGraphUser> user, NSError *error)
{
if(copiedCompletionBlock != nil)
copiedCompletionBlock(user);

// nil out the copied completion block so it is not retained and called everytime the active FBSession's state changes.
copiedCompletionBlock = nil;
}];
}
// Because this method is only concerned with the user logging into Facebook if any other state is triggered call the completion block indicating that there was a failure.
else
{
if(copiedCompletionBlock != nil)
copiedCompletionBlock(nil);

// nil out the copied completion block so it is not retained and called everytime the active FBSession's state changes.
copiedCompletionBlock = nil;
}
}

// This block will exist the lifespan of the application because for some bizarre reason Facebook retains the completion handler for their open active session methods. Throw in some code that will display an error to the user if any session state changes occur that Facebook thinks the user should be aware of. Your code should be always checking if a active Facebook session exists before taking any action so not being aware of these changes should not be any issue. Worst case scenario you can listen for FBSessionDidSetActiveSessionNotification, FBSessionDidUnsetActiveSessionNotification, FBSessionDidBecomeOpenActiveSessionNotification or FBSessionDidBecomeClosedActiveSessionNotification notifications.
if ([error fberrorShouldNotifyUser] == YES)
{
NSString *alertTitle = @"Error logging into Facebook";
NSString *alertMessage = [error fberrorUserMessage];

if ([alertMessage length] == 0)
alertMessage = @"Please try again later.";

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle message:alertMessage delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];

[alertView show];
}
}];
}
// If the user is already logged into Facebook immediately call the completion block with the user object that should have been saved when the user previously logged in.
else
{
if(completionBlock != nil)
completionBlock([self facebookUser]);
}
}

关于ios - 您如何打开一个 FBSession,其完成处理程序不会在每次 session 状态更改时被保留和调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15663301/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com