Вернуть строку и отобразить ее в NSTextField (приложение SwiftUI/macOS)

У меня следующая проблема: я хочу сделать приложение, которое отображает информацию о солнце. Мне удалось распечатать 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
    
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
186
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Сделать назначение в основной очереди, например

DispatchQueue.main.async { [weak self] in
   self?.sunrise1.stringValue = sunrise
}

Большое спасибо, это работает. Могу я спросить вас, где лучше всего изучать SwiftUI и XCode? Это официальная документация Apple или есть лучшие источники.

user14295707 22.12.2020 18:28

На самом деле, лучше иметь завершение в вашем 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, но если вы попытаетесь вернуть другой тип, вы получите ошибку компиляции.

Другие вопросы по теме