У меня следующая проблема: я хочу сделать приложение, которое отображает информацию о солнце. Мне удалось распечатать Sunrise в консоли, однако это не конечная цель. Я хочу отобразить его в NSTextField. Вот тут начинаются проблемы.
Я попытался добавить self.sunrise1.stringValue = sunrise
в private func getData()
. По-видимому, это не работает, и Xcode говорит мне,
NSControl.stringValue должен использоваться только в основном потоке.
Итак, теперь я подумал, что должен вернуть переменную sunrise
. Но когда я добавляю return(sunrise)
Xcode показывает ошибку:
неожиданная непустая ошибка возврата
Итак, мой вопрос: как мне отобразить stringValue
из sunrise
в моем ярлыке sunrise1
?
class ViewController: NSViewController {
@IBOutlet weak var sunrise1: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
let url = "https://api.sunrise-sunset.org/json?lat=36.7201600&lng=-4.4203400"
getData(from: url)
// Do any additional setup after loading the view.
}
private func getData(from url: String) {
let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: {data, response, error in
guard let data = data, error == nil else {
print("something went wrong")
return
}
var result: Response?
do {
result = try JSONDecoder().decode(Response.self, from: data)
}
catch {
print("failed to convert \(error.localizedDescription)")
}
guard let json = result else {
return
}
let sunrise = json.results.sunrise
print(sunrise)
})task.resume()
}
}
struct Response: Codable {
let results: MyResult
let status: String
}
struct MyResult: Codable {
let sunrise: String
let sunset: String
let solar_noon: String
let day_length: String
let civil_twilight_begin: String
let civil_twilight_end: String
let nautical_twilight_begin: String
let nautical_twilight_end: String
let astronomical_twilight_begin: String
let astronomical_twilight_end: String
}
Сделать назначение в основной очереди, например
DispatchQueue.main.async { [weak self] in
self?.sunrise1.stringValue = sunrise
}
На самом деле, лучше иметь завершение в вашем func getData
, поэтому, когда оно отработает, вы обновите свой ярлык в завершение.
В качестве ссылки я могу предложить что-то вроде:
func getData(fromUrl url: String, completion: @escaping (String) -> ()) {
let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { data, response, error in
guard let data = data, error == nil else {
print("something went wrong")
return
}
var result: Response?
do {
result = try JSONDecoder().decode(Response.self, from: data)
}
catch {
print("failed to convert \(error.localizedDescription)")
}
guard let json = result else {
return
}
let sunrise = json.results.sunrise
completion(sunrise)
})
task.resume()
}
И теперь вы можете вызвать свой метод, например, в viewDidLoad() и обновить свою метку следующим образом:
self.getData(fromUrl: "") { sunrise in
DispatchQueue.main.async { [weak self] in
self?.sunrise1.stringValue = sunrise
}
}
Чтобы получить больше информации, вы можете узнать о completion block/handlers
, функциях с дополнениями и почему мы должны обновлять пользовательский интерфейс в основном потоке.
Но когда я добавляю возврат (восход солнца), Xcode показывает ошибку: «неожиданный непустая ошибка возврата».
Если вы хотите, чтобы ваша функция что-то возвращала, вы должны объявить об этом в сигнатуре метода, например:
func itReturnInt() -> Int {
return 1
}
вернет 1, что является Int, но если вы попытаетесь вернуть другой тип, вы получите ошибку компиляции.
Большое спасибо, это работает. Могу я спросить вас, где лучше всего изучать SwiftUI и XCode? Это официальная документация Apple или есть лучшие источники.