无法从同一类中的闭包中更改变量 [swift 3.0]

Posted

技术标签:

【中文标题】无法从同一类中的闭包中更改变量 [swift 3.0]【英文标题】:Cannot change variable from a closure in the same class [swift 3.0] 【发布时间】:2016-09-27 14:59:02 【问题描述】:
var serviceTypeName = [String]()

override func viewDidLoad() 
    super.viewDidLoad()
    getServiceType()
    debugPrint(serviceTypeName)

我尝试从 Web API 获取名称数组,并将其存储到数组 serviceTypeName 中。下面是我获取服务名的函数(我用的是Alamofire lib)

func getServiceType() 
            Alamofire.request(...
                .responseJSON  response in
                    switch response.result 
                    case .success:

                        if let responseValue = response.result.value 
                            var serviceName: [String] = []
                            let json = JSON(responseValue)

                            for (key, subJson):(String, JSON) in json["results"] 

                                if let name = subJson["name"].string 
                                    serviceName.insert(name, at: Int(key)!)

                                
                            
                            self.serviceTypeName = serviceName

                         ...

然而,我在这个函数之后得到了空数组[],就像这个函数没有做任何事情一样。我确保从服务器获得正确的数据,并在每个循环中正确输入serviceName。但我无法将其设置为serviceTypeName。请指出错误?

【问题讨论】:

【参考方案1】:

在这个函数之后我得到了空数组[],就像这个函数没有做任何事情一样。

没错,该函数没有做任何事情。更准确地说,该函数还没有做任何事情。函数后检查值过早,因为回调是异步执行的,数据到达时。

你需要把你的代码分成两部分:

第一部分启动调用,并给它一个回调,将属性设置为从调用接收到的结果 第二部分处理结果,显示属性或执行您计划执行的任何其他操作

一旦回调完成设置属性,它需要启动第二部分的调用,它利用这些属性。

func getServiceType()  // Part 1
    ...
    self.serviceTypeName = serviceName
    dispatch_async(dispatch_get_main_queue()) 
        processServiceName()
    



func processServiceName()  // Part 2
    ... // Do things with self.serviceTypeName

【讨论】:

DispatchQueue.main.async ... 我用这个代替dispatch_async... 会导致错误 @user2174595 我明白了,您使用的是 Swift-3,对吧?你的processServiceName() 函数是做什么的,你会得到什么样的错误? 是的。这可能只是 swift 3.0 中的语法差异。我在 func 中重新加载 UITableView。 @user2174595 它会崩溃,还是不会重新加载数据?对this question 的回答表明您的代码应该可以工作。 谢谢!有用。 @Edgar 的答案也很棒,在 Alamofire 中使用 completionHandler【参考方案2】:

Alamofire 请求是异步的。这意味着您在 getServiceType() 中的代码将与您在 viewDidLoad() 函数中的其余代码分开运行。

debugPrint(serviceTypeName)被调用的时候getServiceType()函数还没有完成处理。

解决这个问题的一种方法是在你的getServiceType() 函数中添加一个completionHandler:

func getServiceType(completionHandler: () -> ()) 
            Alamofire.request(...
                .responseJSON  response in
                    switch response.result 
                    case .success:

                        if let responseValue = response.result.value 
                            var serviceName: [String] = []
                            let json = JSON(responseValue)

                            for (key, subJson):(String, JSON) in json["results"] 

                                if let name = subJson["name"].string 
                                    serviceName.insert(name, at: Int(key)!)

                                
                            
                            self.serviceTypeName = serviceName
                            completionHandler()
                         ...

然后你可以这样调用函数:

override func viewDidLoad() 
    super.viewDidLoad()
    getServiceType() 
        debugPrint(serviceTypeName)
    

在这里,当异步函数触发完成处理程序时,将调用调试打印:在正确的时间。 :)

【讨论】:

这是 Xcode 告诉我添加 func getServiceType(completionHandler: @escaping () -> ()) 的内容。这里的escaping 是什么意思? 没问题!我没有信心向您解释什么是闭包/类型属性,所以我将把它留在这里以获取更多信息:updating-closures-to-swift-3-escaping

以上是关于无法从同一类中的闭包中更改变量 [swift 3.0]的主要内容,如果未能解决你的问题,请参考以下文章

Swift无法使用类型(实例)访问类中的静态变量

是否可以根据从 Swift 中的 UIViewController 继承的类中的另一个来初始化变量?

ChatGPT问答[2]-Python类中的方法是闭包吗?是否拥有闭包的性质?

Swift 5:转义闭包捕获'inout'参数

在同一类中的 setTimeout 期间维护变量

无法访问扩展 Objective-C 类的 Swift 类中的私有变量