2015-02-08 36 views
7

Chcę utworzyć funkcję, aby sprawdzić, czy identyfikator użytkownika jest już w mojej bazie danych.Czy Swift zwraca wartość z asynchronicznego bloku zwracającego puste?

class func checkIfUserExsits(uid:String) -> Bool { 
    userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value, withBlock: { (snapShot: FDataSnapshot!) -> Void in 
       if snapShot.value is NSNull { 
        return false 
       } else { 
        return true 
       } 
    }) 
} 

Jednak observeSingleEventOfType jest API dostarczone przez 3rd party Firebase. Zdefiniowano, aby zwracać Void.

  • (void)observeSingleEventOfType:(FEventType)eventType withBlock:(void (^) (FDataSnapshot *snapshot))block

Błąd: Type 'Void' does not conform to protocol 'BooleanLiteralConvertible'

Doceń każdy rodzaj pomaga.


UPDATE

Staram inny sposób:

class func checkIfExist(uid: String) -> Bool { 
    var answer:Bool = false 
    var text:String = "not yet completed" 
    let queue = dispatch_group_create() 
    dispatch_group_enter(queue) 
     userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value, withBlock: { (snapShot: FDataSnapshot!) -> Void in 
       if snapShot.value is NSNull { 
        text = "This is a new user" 
        answer = false 
        dispatch_group_leave(queue) 
       } else { 
        text = "Found the user in Firebase" 
        answer = true 
        dispatch_group_leave(queue) 
       } 
     }) 
    dispatch_group_wait(queue, DISPATCH_TIME_FOREVER) 
    println(text) 
    return answer 
} 

Jakoś to po prostu zamrozić tam. Wiem, że to podejście może teraz być nietypowe. Ale proszę, pomóż.

Odpowiedz

14

Powinieneś zatrudnić asynchronicznej obsługi ukończenia siebie:

class func checkIfUserExists(uid: String, completionHandler: (Bool) ->()) { 
    userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value) { snapShot in 
     if snapShot.value is NSNull { 
      completionHandler(false) 
     } else { 
      completionHandler(true) 
     } 
    } 
} 

Następnie można nazwać tak:

MyClass.checkIfUserExists(uid) { success in 
    // use success here 
} 

// but not here 

W swojej poprawionej pytanie, wykazać korzystania z grup wysyłki do spraw, aby ta asynchroniczna metoda zachowywała się synchronicznie. (Semafory są również często wykorzystywane do tych samych celów.)

dwie kwestie:

  1. będzie tego impasu, jeżeli wysyła ich obsługi zakończenia powrotem do głównego kolejki (aw wielu przypadkach biblioteki będą to robić aby uprościć życie dla nas), ponieważ przypadkowo blokujesz ten sam wątek, którego próbujesz użyć. Nie wiem, czy to właśnie zrobili tutaj, ale jest prawdopodobne.

    Jeśli chcesz to potwierdzić, tymczasowo usuń grupę wysyłkową, a następnie sprawdź, czy działa w głównym wątku, czy nie.

  2. W żadnym razie nie należy blokować głównego wątku. Zapewnili interfejs asynchroniczny z dobrego powodu, więc powinieneś używać asynchronicznych wzorców podczas wywoływania tego. Nie walcz z asynchronicznymi wzorami, ale raczej je obejmuj.

+0

Dzięki. Zastanawiam się, czy jest jakiś inny, mniej gadatliwy sposób, aby to zrobić. Nie podoba mi się, że mój projekt jest zagnieżdżony w kompletnych blokach wewnątrz kompletnych bloków. –

+0

Dziękuję bardzo Rob. Wiem, że prawdopodobnie robię to w bardzo zły sposób, ale nadal chcę spróbować. Tak jak powiedziałeś, próbuję zsynchronizować tę funkcję. Nie znam semaforów. Zamiast tego próbowałem użyć dispactch_group_wait. Zobacz aktualizację mojego pytania. –

+3

Jeśli wyślą swój przewodnik zakończenia z powrotem do głównej kolejki (w wielu przypadkach zrobią to biblioteki, aby uprościć życie dla nas), zablokujesz główny wątek, czekając, aż biblioteka wyśle ​​obsługę zakończenia do ten sam wątek, który blokujesz. Nie wiem, czy to właśnie tutaj zrobili, ale jest prawdopodobne. Tymczasowo usuń grupę wysyłkową, a następnie sprawdź "NSThread.isMainThread', jeśli chcesz potwierdzić. Ale, znowu, bardziej usilnie zalecałbym blokowanie głównego wątku tylko dlatego, że mniej wygodnie korzystasz z zamknięć i asynchronicznych wzorców. – Rob