首页 > 解决方案 > 为什么不在 Swift Widget 中使用 URLSession

问题描述

我从我的站点创建带有温度的小部件。在标准程序中所有工作,但在结果小部件中我看到“0”(来自var的信息)

这里有错误的代码(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
    }
    
}

在小部件上我看到“0”(来自:var dig:String =“0”),为什么?我在哪里犯错?

这是我的 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)
    }
}

标签: swiftswiftuiwidgeturlsessionwidgetkit

解决方案


URLSession.shared.dataTask异步的,这意味着您需要另一种方式来返回数据。

为此,您可以在getTemp函数中提供完成处理程序:

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
}

如您所见,该getTimeline函数还有一个完成处理程序 - 这允许您在那里执行异步函数:

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

推荐阅读