【问题标题】:'self' captured by a closure before all members were initialized在所有成员初始化之前由闭包捕获的“自我”
【发布时间】:2017-02-22 22:28:18
【问题描述】:

好的,开始吧,这是我的代码:

import UIKit
import ForecastIO

class Weather {
    var temp: Float
    var condition: String
    var wind: Float
    var precip: Float

    init() {
        DarkSkyClient(apiKey: "<api key>").getForecast(latitude: Utils().getLat(), longitude: Utils().getLong()) { result in

            switch result {
            case .success(let currentForecast, _):

                self.temp = (currentForecast.currently?.temperature)!
                self.condition = (currentForecast.currently?.summary)!
                self.wind = (currentForecast.currently?.windSpeed)!
                self.precip = (currentForecast.currently?.precipitationProbability)!

            case .failure(let error):
                print(error)

            }

        }

    }

}

所以我的错误出现了,因为我试图在 API 调用中初始化 temp。我知道这不是最可靠的方法,但我正在尝试首先让它发挥作用。

第一个错误是:

在所有成员初始化之前被闭包捕获的'self'

上线DarkSkyClient(apiKey: "").getForecast(latitude: Utils().getLat(), longitude: Utils().getLong()) { result in

我的第二个错误:

从初始化程序返回而不初始化所有存储的属性

倒数第二个}

现在,显然我没有正确初始化。我找不到正确的方法来完成我的最终目标。也许我这样做完全错了?

【问题讨论】:

  • 一个对象不能异步初始化自己。您的 API 调用应该由另一个对象调用,该对象应该为您的 Weather 类调用初始化程序并传入它从 API 获取的值。
  • @dan 我理解那部分,我只是不明白使用另一个对象的正确方法是什么。 (另外,感谢您的帮助)
  • 你可以将你的成员变量声明为 Optionals
  • @odlund 我试过这个,但我得到了一个意想不到的零。
  • 在执行异步代码之前给所有属性一些默认值。

标签: swift


【解决方案1】:

对我来说,这是因为我没有在初始化程序中调用super.init()

class AnObject: NSObject {
    override init() {
//        super.init()

        let _: ()-> (Void) = {
            print(String(describing: self))
        }
    }
}

【讨论】:

  • 这个答案之所以有效,是因为您、我以及可能您的答案的其他 16 名赞成投票者对情况略有不同:我们的问题类继承自 NSObject。
【解决方案2】:

您有两个选择,将属性声明为可选项,或者使用默认值初始化它们(这意味着它们将是非可选项)

var temp: Float?
var condition: String?
var wind: Float?
var precip: Float?

var temp: Float=0
var condition: String=""
var wind: Float=0
var precip: Float=0

【讨论】:

  • 在第二个选项中,将所有0 更改为0.0,您可以删除所有显式类型声明。
  • @rmaddy 这将使他们成为Doubles(可能需要也可能不需要)
  • @Hamish 真。在发表我的评论后,我确实发生了这种情况。 :)
  • 这个问题是当应用程序运行时,如果我使用选项 1 对它做任何事情,我会得到意想不到的零。如果我使用选项 2,我只会得到我作为占位符输入的值,而不是实际的 API 响应值。并且 0.0 作为浮点数(以及双精度数,如果您没有明确输入 Float: 则默认为
  • 你需要在你使用它的地方重新加载数据的展示,记住这是一个异步调用
【解决方案3】:

我冒险猜测您遇到了并发问题。您可能正试图在对 DarkSkyClient 的异步调用返回之前访问您的对象的属性(如果我弄错了,我提前道歉)。即,事件的顺序是......

  1. Weather 对象已初始化,将 temp 设置为 0
  2. 开始调用 DarkSkyClient,在后台运行
  3. 读取临时变量 - 嘿,它是 0!
  4. 对 DarkSkyClient 的调用完成,将 temp 设置为您真正想要的值。不好

所以你真正需要做的是切换到控制反转模式:

class Weather {
    var temp: Float
    var condition: String
    var wind: Float
    var precip: Float

    init(forecast: Forecast) {
        temp = (forecast.currently?.temperature)!
        condition = (forecast.currently?.summary)!
        wind = (forecast.currently?.windSpeed)!
        precip = (forecast.currently?.precipitationProbability)!
    }

    static func getWeather() {
        DarkSkyClient(apiKey: "<api key>").getForecast(latitude: Utils().getLat(), longitude: Utils().getLong()) { result in

            switch result {
            case .success(let currentForecast, _):
                let weather = Weather(forecast: currentForecast)
                // Display the weather somewhere
                doSomethingWith(weather: weather)
            case .failure(let error):
                print(error)
            }
        }
    }    
}

如果您不熟悉使用异步 API 进行开发,那么值得您阅读该主题;这可能非常棘手(遗憾的是,我没有任何好的入门建议)。 希望这会有所帮助!

【讨论】:

  • 为什么即使是可选的 init() 也会导致同样的问题?
  • 请给我解释一下,当代码甚至无法编译时,他怎么会遇到并发问题?
猜你喜欢
  • 2018-01-18
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 2022-01-15
  • 1970-01-01
相关资源
最近更新 更多