【问题标题】:How to return value from a closure in a Struct in Swift?如何从 Swift 中的 Struct 中的闭包中返回值?
【发布时间】:2020-11-14 17:57:57
【问题描述】:

我正在从网站检索数据。

网络运作良好。从 JSON 中正确解析数据。

几个参考 - 在这个结构中:

  • Replies 是 JSON 的数据模型
  • PrepareQuestions 是一个执行解析的函数(我在同一个 Struct 的扩展中拥有它)

我想在这个结构中包含一个包含所有下载信息的对象(downloadedData - 'Replies' 是带有数据模型的结构),但由于“self 是不可变的捕获”而导致错误。有什么建议么?谢谢!

    struct QuestionsManager {
    
    var downloadedData:Replies?
    
    func useData() {
        manageQuestions(url: K.urlForRetreival, numberOfQuestions: K.numberOfSquares) { [self] (replies, error) in
            if let replies = replies {
                DispatchQueue.main.async {
                    downloadedData = replies // Here I got the error
                }
            }
        }
    }
    
    func manageQuestions(url: String, numberOfQuestions: String, myCompletion: @escaping (Replies?, Error?)->()) {
        let generatedUrl = URL(string: url + numberOfQuestions)!
        let urlSession = URLSession(configuration: .default)
        let task = urlSession.dataTask(with: generatedUrl) { (data, response, error) in
            if error == nil {
                if let fetchedData = data {
                    let fetchedProcessedData = prepareQuestions(data: fetchedData)
                    myCompletion(fetchedProcessedData, nil)
                    return
                }
            } else {
                myCompletion(nil, error)
                return
            }
        }
        task.resume()
    }
}

【问题讨论】:

    标签: swift closures


    【解决方案1】:

    您看到此错误是因为闭包捕获了一个不可变的 self

    就像原始类型(例如Int)一样,structs 是值类型,而 Swift 是根据值类型的不变性概念构建的。

    换句话说,如果你有let questionManager = QuestionManager(),你会期望questionManager 不会改变。即使它是var,它也只能通过调用者的直接操作进行变异,例如questionManager.doMutatingFunc().

    但是,如果允许闭包捕获自身,它可以在稍后修改自身。这是不允许的。

    解决此问题的最简单(唯一?)方法是将QuestionManager 转换为class

    class QuestionManager {
       // ... 
    }
    

    【讨论】:

    • 谢谢 - 它确实有效,我应该考虑一下!生成的“downloadedData”虽然显示为 nil(虽然我确信解析效果很好) - 你认为这取决于网络时间吗?我应该使用完成处理程序解决问题吗?
    【解决方案2】:

    struct 是一个值类型。对于值类型,只有明确的方法 标记为 mutating 可以修改 self 的属性,所以这不是 可能在计算属性中。

    如果您将 struct 更改为一个类,那么您的代码编译时不需要 问题。

    结构是值类型,这意味着它们在被复制时被复制 传递。因此,如果您更改副本,则仅更改该副本, 不是原件,也不是任何其他可能存在的副本。如果 你的结构是不可变的,那么所有的自动副本都是由 按值传递将是相同的。如果你想改变它,你 必须有意识地通过创建结构的新实例来做到这一点 使用修改后的数据。

    来自https://stackoverflow.com/a/49253452/11734662

    【讨论】:

      猜你喜欢
      • 2016-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多