Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

swiftui - Why don't work URLSession in Swift Widget

I create widget with temperature from my site. In standart program all work, but in Widget on result i see "0" (info from var)

Here code with mistake (DataProvider.swift)

import Foundation

class DataProvider {
    
    struct CurrencyJSON: Codable {
        var temp : String
    }
    static func getTemp() -> String {
        
    var dig : String = "0"
    print ("1")
    //on url this data: {temp:3.5}, this is my site, i can do anything format, may be make format: 3.5 (no json)?
    URLSession.shared.dataTask(with: URL(string: "http://example.com/weather.php")! ) {(data, response, error) in
        guard let data = data else { return }
        do {
            let res = try JSONDecoder().decode(CurrencyJSON.self, from: data)
            dig=res.temp
            print ("(dig)")
        } catch let error {
            print("(error)")
        }
    }.resume()
    return dig
    }
    
}

And on widget i see "0" (From this: var dig : String = "0"), why? Where i make mistake?

Here my struct Provider: TimelineProvider:

struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), myString: "...")
    }

    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date(), myString: "...")
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []
        print ("1")
        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 5 {
            let entryDate = Calendar.current.date(byAdding: .second, value: hourOffset * 10, to: currentDate)!
            
            let entry = SimpleEntry(date: entryDate, myString: DataProvider.getTemp())
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}
question from:https://stackoverflow.com/questions/65866198/why-dont-work-urlsession-in-swift-widget

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

URLSession.shared.dataTask is asynchronous which means you need another way to return the data.

For this you can provide a completion handler in the getTemp function:

static func getTemp(completion: @escaping (String) -> Void) { // add completion, don't return anything
    var dig: String = "0"
    URLSession.shared.dataTask(with: URL(string: "http://example.com/weather.php")!) { data, response, error in
        guard let data = data else { return }
        do {
            let res = try JSONDecoder().decode(CurrencyJSON.self, from: data)
            dig = res.temp
            print("(dig)")
        } catch {
            print("(error)")
        }
        completion(dig) // pass the value to the completion handler
    }.resume()
    // return dig // don't return here
}

As you can see, the getTimeline function also has a completion handler - this allows you to execute asynchronous functions there:

func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
    DataProvider.getTemp { myString in
        var entries: [SimpleEntry] = []
        let currentDate = Date()
        for hourOffset in 0 ..< 5 {
            let entryDate = Calendar.current.date(byAdding: .second, value: hourOffset * 10, to: currentDate)!
            
            let entry = SimpleEntry(date: entryDate, myString: myString)
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
...