简体   繁体   中英

Return String and display it in NSTextField (SwiftUI / macOS App)

I have the following problem: I want to make an app which displays information about the sun. I have managed to print the Sunrise in the console, however that's not the final goal. I want to display it in an NSTextField. This is where it starts to get problematic.

I have tried to add self.sunrise1.stringValue = sunrise in the private func getData() . Apparently this doesn't work and Xcode tells me,

NSControl.stringValue must be used in main thread only

So now I thought I have to return the sunrise variable. But when I add return(sunrise) Xcode shows an error:

unexpected non-void return error

So my question is, how do I display the stringValue of sunrise in my label 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
    
}

Make assignment on main queue, like

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

Actually, is better to have completion in your func getData , so when it finished working you will update your label in completion. As reference I may propose something like:

  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()
  }

And now you can call you method in, for example, viewDidLoad() and update your label like that:

self.getData(fromUrl: "") { sunrise in
  DispatchQueue.main.async { [weak self] in
     self?.sunrise1.stringValue = sunrise
  }
}

To get more information you may learn about completion block/handlers , functions with completions and why we must update UI in main thread.

But when I add return(sunrise) Xcode shows an error: "unexpected non-void return error".

If you want your func to return something, you have to declare about that in method signature, for example:

func itReturnInt() -> Int {
  return 1
}

will return 1 which is Int, but if you try to return other type, you will get compilation error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM