2014-10-07 11 views
15
var first_name = "" 

    func problemFunc() { 

     FBRequestConnection.startForMeWithCompletionHandler { (connection: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in 
      if let fbGraphUserDict = result as? Dictionary<String, AnyObject>{ 
       first_name = fbGraphUserDict["first_name"] as NSString 
       println(first_name) 
      } 
     } 
    } 


    PFFacebookUtils.logInWithPermissions(permissions, { 
     (user: PFUser!, error: NSError!) -> Void in 
     if user == nil { 
      NSLog("Uh oh. The user cancelled the Facebook login.") 
     } else if user.isNew { 
      NSLog("User signed up and logged in through Facebook!") 
     } else { 
      NSLog("User logged in through Facebook!") 
      problemFunc() // error is here 

     } 
    }) 

Ten kod znajduje się wewnątrz przycisku @Ibaction. Nie mogę zbudować, ponieważ wywołanie metody problemFunc() wyzwala komunikat o błędzie w tytule tego wpisu. Jeśli przeniesię definicję first_name var do parametru problemFunc, będzie działać poprawnie. Ale potrzebuję go, ponieważ inna funkcja będzie musiała uzyskać dostęp do jego wartości. Naprawdę nie jestem pewien, co powoduje ten problem, jeśli masz wskazówkę, pomóż.Brak odniesienia do funkcji lokalnej przy przechwytywaniu z innej funkcji lokalnej (Swift)

Odpowiedz

27

Użyj zamknięcie zamiast funkcji:

var first_name = "" 

let problemFunc = {() ->() in 

    FBRequestConnection.startForMeWithCompletionHandler { (connection: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in 
     if let fbGraphUserDict = result as? Dictionary<String, AnyObject>{ 
      first_name = fbGraphUserDict["first_name"] as NSString 
      println(first_name) 
     } 
    } 
} 


PFFacebookUtils.logInWithPermissions(permissions, { 
    (user: PFUser!, error: NSError!) -> Void in 
    if user == nil { 
     NSLog("Uh oh. The user cancelled the Facebook login.") 
    } else if user.isNew { 
     NSLog("User signed up and logged in through Facebook!") 
    } else { 
     NSLog("User logged in through Facebook!") 
     problemFunc() // error is here 

    } 
}) 
+0

dzięki, działa, ale z jakiegoś powodu musiałem usunąć: ->() –

+0

Dzięki wielkie! Dobry pomysł, aby uniknąć tej brzydkiej rzeczy – iiFreeman

2

@fluidsonic odpowiedź powinna rozwiązać ten problem. Zauważ jednak, że robisz kod spaghetti, ponieważ modyfikujesz zmienną przechwyconą przez zamknięcie i wykonujesz ją w kontekście innej funkcji. Trudno to sprawdzić, jeśli trzeba debugować, a ogólnie trudniej śledzić, kiedy i jak modyfikowana jest ta zmienna.

Przepływ bardziej liniowy i lepiej czytelny jest zdefiniowanie problemFunc jako funkcję robienia funkcję jako parametr i wywołanie tej funkcji zamiast bezpośredniego ustawiania wartości w first_name zmiennej:

let problemFunc = { (callback: (String -> Void) ->()) in 

    FBRequestConnection.startForMeWithCompletionHandler { (connection: FBRequestConnection!, result: AnyObject!, error: NSError!) -> Void in 
     if let fbGraphUserDict = result as? Dictionary<String, AnyObject>{ 
      let first_name = fbGraphUserDict["first_name"] as NSString 
      callback(first_name) // << here you call the callback passing the `first_name` local variable 
      println(first_name) 
     } 
    } 
} 

i zrobić rzeczywisty przypisanie do first_name w zamknięciu zdefiniowanego podczas wywoływania problemFunc:

PFFacebookUtils.logInWithPermissions(permissions, { 
    (user: PFUser!, error: NSError!) -> Void in 
    if user == nil { 
     NSLog("Uh oh. The user cancelled the Facebook login.") 
    } else if user.isNew { 
     NSLog("User signed up and logged in through Facebook!") 
    } else { 
     NSLog("User logged in through Facebook!") 
     problemFunc { (name: String) -> Void in 
      first_name = name 
     } 
    } 
}) 
+0

dzięki, spróbuj to również –

11

Oto podstawowe zasady w grze: (od docs Apple: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID103)

"Funkcje globalne i zagnieżdżone, wprowadzone w funkcjach, są w rzeczywistości szczególnymi przypadkami zamknięć. Zamknięcia mają jedną z trzech postaci:

  • Funkcje globalne to zamknięcia, które mają nazwę i nie przechwytują żadnych wartości.
  • Funkcje zagnieżdżone to zamknięcia, które mają nazwę i mogą przechwytywać wartości z ich funkcji otaczania.
  • wyrażenia zamykające są nienazwane zamknięcia napisana w lekkim składni, które można uchwycić wartości z otaczającą kontekście.”

czyli to jest ok

func someFunc() { 
    func nestFunc() {} 
} 

ale to nie jest

func someFunc() { 
    func nestFunc() { 
    func nestedFunc2() { } 
    } 
} 

Jeśli spojrzysz na to w Xcode, trzecia funkcja (func nestedFunc2) da ci błąd "Nie można odwołać się do funkcji lokalnej z przechwytywaniem z innego lokalnego f unction "

Najważniejszą funkcją (func someFunc) jest funkcja globalnego zasięgu , która działa jak zwykłe funkcje/metody.

Druga funkcja (func nestFunc) jest zagnieżdżona funkcja który jest nazwany zamknięcie jeden poziom głęboka, że ​​można uchwycić zakres swojej dominującej funkcji globalnej.

Funkcje zagnieżdżone, mogą przechwytywać zakres funkcji globalnej, ale nie obejmują zakresu innej funkcji zagnieżdżonej, ale nie obejmują zakresu .

Dlatego musimy zamknięcie tj

func someFunc() { 
    func nestFunc() { 
     let strictClosure = {() ->() in 
     //this is where you write the code 
     } 
    } 
} 
+0

tak dokładnie! +1 do końca –

+1

Doskonałe wyjaśnienie. Nie miałem pojęcia, co się dzieje, ale naprawdę łatwo to zrozumieć. +1 – TaylorAllred

Powiązane problemy