2013-03-27 2 views
7

Z jakiegoś dziwnego powodu Facebook zdecydował się na tworzenie programów obsługi zakończeń, które w rzeczywistości są tylko obserwatorami powiadomień. Ignorując, dlaczego to robią, potrzebuję jakiegoś sposobu, aby złożyć wniosek o otwarcie sesji FBS i mieć wywołanie zwrotne tylko raz, ponieważ obiekty wewnątrz wywołania zwrotnego NIE mogą zostać zachowane.Jak otworzyć FBSession z procedurą obsługi zakończenia, która nie zostanie zachowana i wywołana przy każdej zmianie stanu sesji?

Jeśli użytkownik naciśnie przycisk, a sesja na Facebooku z opcjami "publish_actions" nie jest otwarta, powinien zostać wyświetlony wskaźnik aktywności i uniemożliwić interakcję z interfejsem użytkownika podczas otwierania sesji Facebook.

Oto metoda, która jest używana do logowania na Facebooku:

- (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]); 
    } 
} 

Jeśli procedura obsługi zakończenie nie była zachowana (ponownie z powodów, które sprawiają, że nie niecodzienna sens, ponieważ NSNotifications są księgowane po zmianie stany sesja) wtedy ta metoda doskonale by działała.

Ponieważ aplikacja nie krąży wokół Facebooka, nie interesuje mnie, kiedy zmienia się stan sesji. Jeśli użytkownik spróbuje udostępnić coś na Facebooku, a aktywna sesja nie zostanie otwarta, proces logowania zostanie uruchomiony, a jeśli sesja zostanie otwarta, proces udostępniania będzie kontynuowany. W przeciwnym razie użytkownikowi zostanie wyświetlony komunikat o błędzie.

Czy ktoś mógłby wyjaśnić, w jaki sposób Facebook spodziewa się, że tego rodzaju funkcjonalność zostanie zaimplementowana, ponieważ wydaje się być dość powszechnym przypadkiem użycia i zanim ktoś wspomina "dlaczego nie używasz domyślnych okien dialogowych na Facebooku", to dlatego, że niestandardowy interfejs użytkownika musi być przedstawiane użytkownikowi w celu zebrania konkretnych informacji używanych dla postów Open Graph.

Odpowiedz

7

Jeśli nie dbam o otrzymaniu zmiany stanu od FBSessionStateHandler jak ja wtedy poniższy kod powinien pozwalają, aby zalogować się do Facebooka i dostarczy Ci bloku ukończenia że nie jest zatrzymany.

Blok zakończenia, który jest przekazywany do metody, będzie zawsze używany, gdy wystąpi jakakolwiek zmiana stanu, a następnie natychmiast zostanie usunięty, tak że w przypadku wystąpienia innej zmiany stanu, zostanie zignorowany.

1

Sposób, w jaki zaimplementowałem podobne zachowanie, polega na umieszczeniu mojej logiki sesji w pojedynczej sesji. Singleton implementuje procedurę obsługi zakończenia, która może być bezpiecznie wywoływana przez FB, gdy sesja się zmienia. Mój program obsługi zakończenia wysyła następnie własne powiadomienia dla innych kontrolerów, aby obserwować je w razie potrzeby.

Załóżmy, że masz singleton MySession, w którym zdefiniowano niektóre metody i powiadomienia dotyczące uwierzytelniania FB. Twoja logika widok kontroler byłoby coś takiego:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // observe MySession notifications 
    [MySession.sharedSession addObserver:self]; 
} 

- (void)dealloc 
{ 
    // stop observing MySession notifications 
    [MySession.sharedSession removeObserver:self]; 
} 

// this is a user action that requires FB auth 
- (void)someActionRequiringFacebookAuth 
{ 
    if (![MySession.sharedSession isLoggedIntoFacebook]) { 
     self.postAuthAction = @selector(someActionRequiringFacebookAuth); 
     [MySession.sharedSession loginToFacebook]; 
    } 

    else { 
     // perform action 
    } 
} 

// notification posted by MySession before a FB auth attempt 
- (void)mySessionWillAttemptFacebookAuth:(NSNotification *)notification 
{ 
    [self startLoadingAnimation]; 
} 

// notification posted by MySession if a FB auth attempt succeeds 
- (void)mySessionDidAuthWithFacebook:(NSNotification *)notification 
{ 
    [self stopLoadingAnimation]; 
    if (self.postAuthAction) { 
     [self performSelector:self.postAuthAction]; 
     self.postAuthAction = nil; 
    } 
} 

// notification posted by MySession if a FB auth attempt fails 
- (void)mySessionFacebookAuthDidFail:(NSNotification *)notification 
{ 
    [self stopLoadingAnimation]; 
    // display error if desired 
    self.postAuthAction = nil; 
} 
+0

Wolałbym rozwiązanie, które nie wymagałoby wielu deklaracji metod i dodawania/usuwania wywołań obserwatora. Dla uproszczenia szukam sposobu na obsłużenie całej mojej logiki wewnątrz metody someActionRequiringFacebookAuth. –