无法从处理程序访问类中存在的变量

时间:2016-11-29 09:37:53

标签: ios iphone swift swift2 swift3

import UIKit

class ViewController: UIViewController
{

    var icnNum : Int64 = 0

    let stopHandler =
        {
            (action:UIAlertAction!) -> Void in

            let num = icnNum
    }


    func showAlert( userStatus: String )
    {

        let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)

        alert.title = "What you want to do?"

        alert.addAction(UIAlertAction(title: "Stop", style: .default, handler: stopHandler))

    }



}

我不知道如何从处理程序访问icnNum。我得到了以下错误。我知道我无法直接访问该变量但是方式是什么。

实例成员' icnNum'不能在类型' ViewController'

上使用

3 个答案:

答案 0 :(得分:5)

showAlert()函数中定义stopHandler闭包,它应该可以工作。

class ViewController: UIViewController
{
    var icnNum : Int64 = 0

        func showAlert( userStatus: String ) {
            let stopHandler = { (action:UIAlertAction!) -> Void in
                let num = self.icnNum
            }

            let alert = UIAlertController(title: "", message: "", preferredStyle: .Alert)
            alert.title = "What you want to do?"

            alert.addAction(UIAlertAction(title: "Stop", style: .Default, handler: stopHandler))
        }   
    }
}

编译器将强制您编写self.icnNum而不是icnNum,以明确闭包将保留对self的引用。

将stopHandler闭包存储为变量,就像在示例中一样,将创建循环引用。您的ViewController实例拥有对stopHandler闭包的强引用,闭包拥有对self的强引用(这是指向ViewController实例的指针)。

如果要重用stopHandler

,请更新
class ViewController: UIViewController {      
    var icnNum : Int64 = 0
    var stopHandler: ((action:UIAlertAction!) -> Void)?

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        self.stopHandler = { [weak self] (action:UIAlertAction!) -> Void in
            let num = self?.icnNum
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    func showAlert( userStatus: String )
    {
        let alert = UIAlertController(title: "", message: "", preferredStyle: .Alert)
        alert.title = "What you want to do?"

        alert.addAction(UIAlertAction(title: "Stop", style: .Default, handler: stopHandler))      
    }
}

设置stopHandler闭包时请注意[weak self]。这将阻止闭包保持对自身的强烈引用并避免上述循环引用。

更多详情请见:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID57

答案 1 :(得分:2)

你可以这样写近距离

 let stopHandler = {
        (icnNum: Int64 ,action:UIAlertAction!) -> Void in

        let num = icnNum
}

虽然这样称呼它更接近

alert.addAction(UIAlertAction(title: "Stop", style: .default, handler: stopHandler(self.icnNum, UIAlertAction!)))

答案 2 :(得分:1)

您可以将方法作为处理程序传递。这避免了需要在周围浮动的裸露闭合。

class ViewController: UIViewController {

    var icnNum : Int64 = 0

    func stopHandler(_ action: UIAlertAction) {
        let num = icnNum
    }

    func showAlert(userStatus: String) {
        let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)

        alert.title = "What you want to do?"

        alert.addAction(UIAlertAction(title: "Stop", style: .default, handler: stopHandler))
    }

}

<强>更新

这样的处理程序的预期行为是使用可以包含本地上下文的闭包。

func showAlert(userStatus: String) {
    let localContext = "Local information"
    // …
    alert.addAction(UIAlertAction(title: "Stop", style: .default) { action in
        if localContext == "Local information" {
           // Do Something
        }
    })
}

但是,您没有本地环境。您正在使用的上下文包含在对象实例中。

func showAlert(userStatus: String) {
    // …
    alert.addAction(UIAlertAction(title: "Stop", style: .default, handler: stopHandler))
}

因为您的处理程序中没有本地使用的内容,所以您不需要关闭。

func stopHandler(_ action: UIAlertAction) {
    let num = icnNum
}

将执行与闭包处理程序相同的操作,但会为您提供对象实例的上下文。