无法从另一个本地函数(swift)中捕获本地函数

时间:2014-10-07 13:50:14

标签: ios swift

 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

        }
    })

此代码位于@Ibaction按钮内。我无法构建,因为对problemFunc()的调用会触发此帖子标题中的错误消息。如果我在problemFunc中移动first_name var定义,它将正常工作。但是我需要它,因为另一个函数需要访问它的值。 我真的不确定导致这个问题的原因,如果你有线索,请帮忙。

3 个答案:

答案 0 :(得分:27)

使用闭包而不是函数:

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

    }
})

答案 1 :(得分:11)

以下是游戏中的基本原则:(来自Apple的文档:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID103

&#34;函数中引入的全局函数和嵌套函数实际上是闭包的特例。闭包采用以下三种形式之一:

  • 全局函数是具有名称且不捕获任何值的闭包。
  • 嵌套函数是具有名称的闭包,可以从其封闭函数中捕获值。
  • Closure表达式是一种未命名的闭包,用轻量级语法编写,可以从周围的上下文中捕获值。&#34;

即没关系

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

但这不是

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

如果你在Xcode中看到这个,第三个函数(func nestedFunc2)会给你错误&#34;不能从另一个本地函数中引用本地函数&#34;

top函数(func someFunc)是一个全局范围函数,它们就像常规函数/方法一样工作。

第二个函数(func nestFunc)是一个嵌套函数,它是一个深层的命名闭包,可以捕获其父全局函数的范围。

嵌套函数可以捕获全局函数的范围,但另一个嵌套函数的范围。

这就是为什么我们需要一个闭包,即

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

答案 2 :(得分:2)

@pluidsonic答案应该解决问题。但请注意,您正在执行一些意大利面条代码,因为您正在修改由闭包捕获的变量,并在另一个函数的上下文中执行。如果你需要调试那么很难跟踪,更常见的是难以跟踪修改变量的时间和方式。

更线性且更易读的流程是将problemFunc定义为将函数作为参数并调用该函数而不是直接在first_name变量中设置值的函数:

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)
        }
    }
}

并在调用first_name时定义的闭包中对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
        }
    }
})