如何使用 DispatchGroup 在 while 循环中将值设置为条件?

How to set a value as a condition in while loop using DispatchGroup?

我目前正在使用 SwiftUI 开发应用程序。

我想使用从使用 DispatchGroupwhile 循环创建的值作为 while 循环的条件。

但是我的代码不起作用... 我的目标是从开始日期开始获得超过设定总温度的日期。

我该如何解决这个问题?


已更新

例如:

如果我像下面这样调用方法。

makeGetCallDateOverSetTemp(start_date:"2020-11-01", set_temp:100)

while 循环在此处停止并获得 2020-11-04 作为超过设定温度的那一天。


AppState.swift

@Published var weatherInfos:[WeatherInfos]?


func makeGetCallDateOverSetTemp(start_date:String, set_temp:Int){
    
    let start_date = self.dateFromString(string: start_date, format: "yyyy/MM/dd")
    var addDays = 0
    var totalTemp:Float = 0.0
    
    let group = DispatchGroup()
   
    // Set up the URL request
    while Float(set_temp) < totalTemp {
        
        let start_date = Calendar.current.date(byAdding: .day, value: addDays, to: start_date)
        let url_start_date = self.stringFromDate(date: start_date!, format: "yyyy-MM-dd")
        
        let endpoint: String = "https://sample.com/api/weather/?start_date=\(url_start_date)"
        addDays += 1
        
        guard let url = URL(string: endpoint) else {
            print("Error: cannot create URL")
            continue
        }
        var urlRequest = URLRequest(url: url)
        urlRequest.addValue("token xxxxxxxxxxx", forHTTPHeaderField: "authorization")
        // set up the session
        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config)
        // make the request
        group.enter()
        let task = session.dataTask(with: urlRequest) {(data, response, error) in
            guard error == nil else {
                print("error calling GET")
                return
            }
            // make sure we got data
            guard let responseData = data else {
                print("Error: did not receive data")
                return
            }
            // check for any errors
            defer { group.leave()}
            // parse the result as JSON, since that's what the API provides
            DispatchQueue.main.async {
                do{
                    self.weatherInfos = try JSONDecoder().decode([WeatherInfos].self, from: responseData)
                    for info in self.weatherInfos!{
                        totalTemp += info.temp
                    }
                }catch{
                    print("Error: did not decode")
                    return
                }
            }
        }
        task.resume()
    }
    group.notify(queue: .main){
    print(url_start_date)
    }
}

func stringFromDate(date: Date, format: String) -> String {
    let formatter: DateFormatter = DateFormatter()
    formatter.calendar = Calendar(identifier: .gregorian)
    formatter.dateFormat = format
    return formatter.string(from: date)
}

func dateFromString(string: String, format: String) -> Date {
    let formatter: DateFormatter = DateFormatter()
    formatter.calendar = Calendar(identifier: .gregorian)
    formatter.dateFormat = format
    return formatter.date(from: string) ?? Date()
}

jsonModel.swift

struct WeatherInfos:Codable,Identifiable {
    var id: Int
    var temp: Float
}

条件依赖于异步任务结果的while循环是不可能的。

这是一个独立的通用示例,在 Playground 中递归到 运行。

静态数据是结构体、数组、队列和阈值

struct Item {
    let date : String
    let values : [Int]
}

let items = [Item(date: "2020-02-01", values: [1, 3, 5]),
             Item(date:"2020-02-02", values:[2, 4, 6]),
             Item(date: "2020-02-03", values:[3, 5, 7])]

let queue = DispatchQueue(label: "Foo")
let threshold = 25

变量是指数和积温

var temp = 0
var index = 0

如果尚未达到阈值,函数 getData 会调用自身传递下一个 item。异步任务用asyncAfter.

模拟

最终函数 notify 被调用。

func notify(date : String) {
    DispatchQueue.main.async{ print(date, temp) }
}

func getData(date: String, values :[Int]) {
    queue.asyncAfter(deadline: .now() + 1) {
        for value in values {
            temp += value
            if temp >= threshold {
                notify(date: date)
                return
            }
        }
        index += 1
        if index < items.count {
            let nextItem = items[index]
            getData(date: nextItem.date, values: nextItem.values)
        } else {
            notify(date: "\(date) – temperature below threshold")
        }
    }
}

let firstItem = items[index]
getData(date: firstItem.date, values: firstItem.values)