Firebase observeEventType no se dispara después de FirebaseSimpleLogin usando Facebook?

Estoy probando el código basado en el ejemplo firechat-ios . He agregado la FirebaseSimpleLogin llamada loginToFacebookAppWithId y la he configurado para que un controller de vista realice el inicio de session y luego las transiciones a un controller de vista diferente que contenga la lógica de chat:

self.firebase = [[Firebase alloc] initWithUrl:@"https://xxxxx.firebaseio.com/"]; [self observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { NSLog(@"%@", snapshot.value); // Add the chat message to the array. [self.chat addObject:snapshot.value]; // Reload the table view so the new message will show up. [self.tableView reloadData]; [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }]; FirebaseSimpleLogin *authClient = [[FirebaseSimpleLogin alloc] initWithRef:self.firebase]; [authClient loginToFacebookAppWithId:kFacebookAppID permissions:@[@"email"] audience:ACFacebookAudienceOnlyMe withCompletionBlock:^(NSError *error, FAUser *user) { if (error != nil) { // There was an error logging in NSLog(@"facebook error"); } else { // We have a logged in facebook user NSLog(@"facebook logged in"); [authClient checkAuthStatusWithBlock:^(NSError* error, FAUser* user) { if (error != nil) { // Oh no! There was an error performing the check NSLog(@"auth error"); } else if (user == nil) { // No user is logged in NSLog(@"auth not logged in"); } else { // There is a logged in user NSLog(@"auth logged in"); // segue to the chat view controller [self performSegueWithIdentifier:@"segueToViewController" sender:self]; } }]; } }]; 

Aquí están las reglas de la base de fuego:

 { "rules": { ".read": "auth != null", ".write": "auth != null" } } 

El problema es que, aproximadamente el 10% del time, UITableView de los posts de chat está en blanco y no veo inputs de posts de chat en el logging. He intentado jugar con el order de observeEventType, poniéndolo antes y después de la llamada loginToFacebookAppWithId.

Me pregunto si hay una condición de carrera donde quizás lleguen los posts antes de que llame a observeEventType. He comprobado el valor de retorno de observeEventType y obtengo un FirebaseHandle de 1 incluso cuando no llegan posts. También he actualizado el marco de firebase que viene con firechat ios a https://cdn.firebase.com/ObjC/Firebase.framework-LATEST.zip y todavía falla.

Pensé que tal vez la connection se networkingujo, pero puedo publicar posts con childByAutoId después de haber autenticado y verlos aparecer en el server de firebase. Nunca recibí ningún post.

Me pregunto si está tratando de enviarme los posts en el breve momento antes de autenticarme y fallar porque no tengo permiso de lectura. ¿Hay alguna forma de retrasar las observaciones del evento hasta después de que estoy?

He intentado todo lo que puedo pensar, pero no puedo hacer que funcione de manera confiable.

———- ACTUALIZACIÓN ———-

Parece que puedo iniciar session cada vez que escribo mis cnetworkingenciales manualmente. Actualmente estoy buscando un inicio de session exitoso anterior con:

 [FBSession openActiveSessionWithAllowLoginUI:false] 

Para determinar si inicié session con éxito en el último lanzamiento de la aplicación. Si falla, voy a un controller de vista para FirebaseSimpleLogin. Pero si funciona, llamo a FirebaseSimpleLogin en el controller de vista actual y espero hasta que tenga éxito en segundo plano.

Estoy ejecutando en el simulador, así que intenté eliminar las preferences en:

 ~/Library/Application Support/iPhone Simulator/7.0.3/Applications/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/Library/Preferences/com.xxxxxxxxxx.plist 

y el relanzamiento, lo que me obliga a volver a autenticar. Luego intenté escribir mis cnetworkingenciales e iniciar session 25 veces sin problemas.

Entonces, creo que el problema está de alguna manera relacionado con intentar iniciar session con Facebook antes de usar FirebaseSimpleLogin, o iniciar session con las cnetworkingenciales del lanzamiento anterior (sin mostrar el cuadro de dialog de inicio de session). Todavía estoy tratando de networkingucir al culpable.

———- ACTUALIZACIÓN 2 ———-

Solo quería agregar una nota que después de más testings, encontré que la llamada a:

 [FBSession openActiveSessionWithAllowLoginUI:false] 

no tiene efecto en FirebaseSimpleLogin. Si omito esa llamada por completo y simplemente sustituyo verdadero o falso allí, puedo reproducir el problema. El problema resultó ser una condición de carrera, vea mi respuesta a continuación.

    Finalmente me di count de lo que estaba sucediendo, se debió a una suposition errónea de mi parte sobre las devoluciones de llamada de posts de UIViewController y CFRunLoop .

    El código de muestra en mi pregunta se destiló desde mi código real para eliminar las llamadas extrañas, pero resulta que la parte que eliminé fue realmente la culpable. Había escrito una function para iniciar session y esperar hasta el éxito o el fracaso in situ (en lugar de recibir la respuesta en un bloque más adelante) utilizando un ciclo de ejecución:

     -(bool)loginUsingFacebookReturningError:(NSError**)error andUser:(FAUser**)user { __block NSError *errorTemp; __block FAUser *userTemp; [self loginUsingFacebookWithCompletionBlock:^(NSError *error, FAUser *user) { errorTemp = error; userTemp = user; CFRunLoopStop(CFRunLoopGetCurrent()); }]; CFRunLoopRun(); // needs a timeout or way for the user to cancel but I haven't implemented it yet if(error) *error = errorTemp; if(user) *user = userTemp; return !errorTemp && userTemp; } -(void)loginUsingFacebookWithCompletionBlock:(void (^)(NSError* error, FAUser* user))block { FirebaseSimpleLogin *authClient = [[FirebaseSimpleLogin alloc] initWithRef:self.firebase]; [authClient loginToFacebookAppWithId:kFacebookAppID permissions:@[@"email"] audience:ACFacebookAudienceOnlyMe withCompletionBlock:^(NSError *error, FAUser *user) { if (error != nil) { // There was an error logging in NSLog(@"facebook error"); block(error, nil); } else { // We have a logged in facebook user NSLog(@"facebook logged in"); [authClient checkAuthStatusWithBlock:block]; } }]; } 

    Esto se llamó con:

     NSError *error; FAUser *user; bool success = [self loginUsingFacebookReturningError:&error andUser:&user]; 

    La forma de inicio de sessionUsingFacebookReturningError funciona, llama a loginUsingFacebookWithCompletionBlock que dispara los posts loginToFacebookAppWithId y checkAuthStatusWithBlock como de costumbre, pero luego comienzo un ciclo de ejecución. El ciclo de ejecución permite que el process se realice en segundo plano, aunque el hilo principal se pausa en CFRunLoopRun () hasta que el bloque de finalización llama a CFRunLoopStop ().

    Lo que no me había dado count es que los loops de ejecución continúan procesando los posts de la aplicación en segundo plano. Así que mientras pensaba que el flujo de progtwig se había detenido en viewDidLoad, en realidad había continuado y llamado viewWillAppear, que es donde había realizado mi llamada a observeEventType (porque supuse que la authentication estaría completa para cuando el progtwig llegó).

    Esto creó una condición de carrera en la que el progtwig adjuntó la callback observeEventType durante el time en que Facebook y Firebase se autenticaron. El 90% del time, la authentication se había completado antes de que se llamara a observeEventType, pero el 10% del time hubo retraso o demoras en la networking y se llamó prematuramente a observeEventType.

    Solucioné el problema moviendo el código de FirebaseSimpleLogin a su propio controller de vista en el guión gráfico y utilizando el bloque de finalización para iniciar el segundo al siguiente controller de vista, que instaló la callback observeEventType.

    Por lo tanto, para resumir: la solución es llamar a la authentication de FirebaseSimpleLogin, y luego DESPUÉS de que haya finalizado y se haya completado el bloque de finalización, llame a observeEventType. De lo contrario, las reglas de Firebase denegarán su request para ver datos que solo son visibles para los usuarios autenticados (lo cual es correcto).

    Aquí está el código final, no probado, pero el método funciona:

     // only global for illustration purposes, should really go in a singleton or AppDelegate, or be passed through the segue to the next view controller Firebase *gFirebase; // LoginViewController (root view controller in storyboard) - (void)viewDidLoad { [super viewDidLoad]; gFirebase = [[Firebase alloc] initWithUrl:@"https://xxxxx.firebaseio.com/"]; FirebaseSimpleLogin *authClient = [[FirebaseSimpleLogin alloc] initWithRef:gFirebase]; [authClient loginToFacebookAppWithId:kFacebookAppID permissions:@[@"email"] audience:ACFacebookAudienceOnlyMe withCompletionBlock:^(NSError *error, FAUser *user) { if (error != nil) { // There was an error logging in NSLog(@"facebook error"); } else { // We have a logged in facebook user NSLog(@"facebook logged in"); [authClient checkAuthStatusWithBlock:^(NSError* error, FAUser* user) { if (error != nil) { // Oh no! There was an error performing the check NSLog(@"auth error"); } else if (user == nil) { // No user is logged in NSLog(@"auth not logged in"); } else { // There is a logged in user NSLog(@"auth logged in"); // segue to the chat view controller [self performSegueWithIdentifier:@"segueToViewController" sender:self]; } }]; } }]; } // ViewController (destination of segueToViewController) - (void)viewDidLoad { [super viewDidLoad]; [gFirebase observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { NSLog(@"%@", snapshot.value); // Add the chat message to the array. [self.chat addObject:snapshot.value]; // Reload the table view so the new message will show up. [self.tableView reloadData]; [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }]; }