Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在swift中同步循环_Swift - Fatal编程技术网

如何在swift中同步循环

如何在swift中同步循环,swift,Swift,我正在尝试编写一个列表排序算法,我使用一个网络调用(API请求)到GoogleMapsAPI获取列表中两点之间距离的信息 我使用while循环,并在列表上迭代,直到列表的大小为0 在每次迭代中,我进行一次网络调用,在它响应之后,我从列表中删除一些内容 我已经尝试在下面的代码中使用信号量,但它并没有像预期的那样工作 let semaphore = DispatchSemaphore(value: 1) let dispatchQueue = DispatchQueue(label: "taskQu

我正在尝试编写一个列表排序算法,我使用一个网络调用(API请求)到GoogleMapsAPI获取列表中两点之间距离的信息

我使用while循环,并在列表上迭代,直到列表的大小为0

在每次迭代中,我进行一次网络调用,在它响应之后,我从列表中删除一些内容

我已经尝试在下面的代码中使用信号量,但它并没有像预期的那样工作

let semaphore = DispatchSemaphore(value: 1)
let dispatchQueue = DispatchQueue(label: "taskQueue")

dispatchQueue.async {
  while unvistedPoints.count > 0{
    print("The size of the list is ", unvisited.count)
    self.findNextVistablePoint(visited: visitedPoints, unvisted: unvistedPoints, completion: { (pointToVisit) in
      let indexofPointToVisit = unvistedPoints.firstIndex(where: {$0 === pointToVisit})
      unvistedPoints.remove(at: indexofPointToVisit!)
      visitedPoints.append(pointToVisit)
      semaphore.signal()
    })
  semaphore.wait()
}

print语句应该打印6,5,4,3,2,1。

等待应该在网络请求之前进行。此外,这里确实没有理由使用dispatchQueue asynch,因为循环所做的工作非常少(网络请求已经是异步的),而且我看不到在这里使用while循环和在可以使用for循环时对数组进行变异的价值。以下是一个例子:

import PlaygroundSupport
import UIKit

struct StarwarsCharacter: Codable {
    let name: String
}

enum APIResult<T> {
    case failure(Error), success(T)
}

func getCharactersSerially(completion: @escaping (APIResult<StarwarsCharacter>) -> ()) {
    var characters: [StarwarsCharacter] = []
    let semaphore = DispatchSemaphore(value: 1)
    let urls = (1...9).map {"https://swapi.co/api/people/\($0)"}.compactMap(URL.init(string:))
    urls.forEach { url in
        semaphore.wait()
        print("starting request for \(url) at \(Date())")
        URLSession.shared.dataTask(with: url) { data, response, error in
            print("completed request for \(url) at \(Date())")
            defer {
                semaphore.signal()
            }
            guard error == nil,
                let data = data,
                let character = try? JSONDecoder().decode(StarwarsCharacter.self, from: data) else {
                    completion(.failure(error ?? NSError()))
                    return
            }
            completion(.success(character))
            }.resume()
    }
}

PlaygroundPage.current.needsIndefiniteExecution = true
getCharactersSerially() { result in
    switch result {
    case .failure(let error):
        print(error.localizedDescription)
    case .success(let character):
        print(character.name)
    }
}
导入PlaygroundSupport
导入UIKit
结构starwarschracter:Codable{
let name:String
}
枚举结果{
案例失败(错误),成功(T)
}
func getCharactersSeries(完成:@escaping(apireult)->()){
变量字符:[starwarschracter]=[]
让信号量=分派信号量(值:1)
让URL=(1…9).map{”https://swapi.co/api/people/\($0)“}.compactMap(URL.init(字符串:))
url.forEach{url在
信号量。等待()
打印(“在\(日期())开始请求\(url))
URLSession.shared.dataTask(with:url){data,response,中的错误
打印(“在\(日期())完成\(url)请求”)
推迟{
信号量
}
保护错误==零,
让数据=数据,
让character=try?JSONDecoder().decode(starwarschracter.self,from:data)else{
完成(.failure(错误??NSError()))
返回
}
完成(.success(字符))
}1.简历()
}
}
PlaygroundPage.current.NeedsDefiniteExecution=true
GetCharactersSerial(){结果为
切换结果{
案例。失败(let错误):
打印(错误。本地化描述)
案例。成功(让角色):
打印(字符.名称)
}
}

等待应该在网络请求之前进行。此外,这里确实没有理由使用dispatchQueue asynch,因为循环所做的工作非常少(网络请求已经是异步的),而且我看不到在这里使用while循环和在可以使用for循环时对数组进行变异的价值。以下是一个例子:

import PlaygroundSupport
import UIKit

struct StarwarsCharacter: Codable {
    let name: String
}

enum APIResult<T> {
    case failure(Error), success(T)
}

func getCharactersSerially(completion: @escaping (APIResult<StarwarsCharacter>) -> ()) {
    var characters: [StarwarsCharacter] = []
    let semaphore = DispatchSemaphore(value: 1)
    let urls = (1...9).map {"https://swapi.co/api/people/\($0)"}.compactMap(URL.init(string:))
    urls.forEach { url in
        semaphore.wait()
        print("starting request for \(url) at \(Date())")
        URLSession.shared.dataTask(with: url) { data, response, error in
            print("completed request for \(url) at \(Date())")
            defer {
                semaphore.signal()
            }
            guard error == nil,
                let data = data,
                let character = try? JSONDecoder().decode(StarwarsCharacter.self, from: data) else {
                    completion(.failure(error ?? NSError()))
                    return
            }
            completion(.success(character))
            }.resume()
    }
}

PlaygroundPage.current.needsIndefiniteExecution = true
getCharactersSerially() { result in
    switch result {
    case .failure(let error):
        print(error.localizedDescription)
    case .success(let character):
        print(character.name)
    }
}
导入PlaygroundSupport
导入UIKit
结构starwarschracter:Codable{
let name:String
}
枚举结果{
案例失败(错误),成功(T)
}
func getCharactersSeries(完成:@escaping(apireult)->()){
变量字符:[starwarschracter]=[]
让信号量=分派信号量(值:1)
让URL=(1…9).map{”https://swapi.co/api/people/\($0)“}.compactMap(URL.init(字符串:))
url.forEach{url在
信号量。等待()
打印(“在\(日期())开始请求\(url))
URLSession.shared.dataTask(with:url){data,response,中的错误
打印(“在\(日期())完成\(url)请求”)
推迟{
信号量
}
保护错误==零,
让数据=数据,
让character=try?JSONDecoder().decode(starwarschracter.self,from:data)else{
完成(.failure(错误??NSError()))
返回
}
完成(.success(字符))
}1.简历()
}
}
PlaygroundPage.current.NeedsDefiniteExecution=true
GetCharactersSerial(){结果为
切换结果{
案例。失败(let错误):
打印(错误。本地化描述)
案例。成功(让角色):
打印(字符.名称)
}
}

下面是一些简化的操场代码,演示如何使用信号量来确保您的请求以串行方式执行:

import UIKit
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

class SomeAsyncClass {

    var unvistedPoints = [ 6,5,4,3,2,1 ]
    let dispatchQueue = DispatchQueue(label: "taskQueue") // serial queue
    let semaphore = DispatchSemaphore(value: 1)

    public func doAsyncStuff() {
        for point in self.unvistedPoints {
            print("Queuing point \(point)")
            dispatchQueue.async {
                // block before sending the network request
                self.semaphore.wait()
                self.makeFakeNetworkRequest(point, completion: {
                    // request complete
                    print("Completed \(point)")
                    self.semaphore.signal()
                })
            }
        }
    }

    func makeFakeNetworkRequest(_ point:Int, completion:()->()) {
        let interval = TimeInterval(exactly: (arc4random() % 3) + 1)!
        print("Point \(point): Sleeping for: \(interval)")
        Thread.sleep(forTimeInterval: interval)
        print("Point \(point): Awoken after: \(interval)")
        completion()
    }
}

var c = SomeAsyncClass()
c.doAsyncStuff()
以下是输出:

Queuing point 6
Queuing point 5
Queuing point 4
Point 6: Sleeping for: 3.0
Queuing point 3
Queuing point 2
Queuing point 1
Point 6: Awoken after: 3.0
Completed 6
Point 5: Sleeping for: 3.0
Point 5: Awoken after: 3.0
Completed 5
Point 4: Sleeping for: 3.0
Point 4: Awoken after: 3.0
Completed 4
Point 3: Sleeping for: 3.0
Point 3: Awoken after: 3.0
Completed 3
Point 2: Sleeping for: 3.0
Point 2: Awoken after: 3.0
Completed 2
Point 1: Sleeping for: 3.0
Point 1: Awoken after: 3.0
Completed 1

尽管如此,这并不是最好的方法。您最好使用为此目的而设计的iOS结构,即OperationQueue——它具有细粒度并发控制(
maxConcurrentOperationCount
),并且可以用作URLSession(
delegateQueue
)的基础。如果适合您的需要,我建议您使用该结构。

下面是一些简化的操场代码,演示如何使用信号量来确保您的请求以串行方式执行:

import UIKit
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

class SomeAsyncClass {

    var unvistedPoints = [ 6,5,4,3,2,1 ]
    let dispatchQueue = DispatchQueue(label: "taskQueue") // serial queue
    let semaphore = DispatchSemaphore(value: 1)

    public func doAsyncStuff() {
        for point in self.unvistedPoints {
            print("Queuing point \(point)")
            dispatchQueue.async {
                // block before sending the network request
                self.semaphore.wait()
                self.makeFakeNetworkRequest(point, completion: {
                    // request complete
                    print("Completed \(point)")
                    self.semaphore.signal()
                })
            }
        }
    }

    func makeFakeNetworkRequest(_ point:Int, completion:()->()) {
        let interval = TimeInterval(exactly: (arc4random() % 3) + 1)!
        print("Point \(point): Sleeping for: \(interval)")
        Thread.sleep(forTimeInterval: interval)
        print("Point \(point): Awoken after: \(interval)")
        completion()
    }
}

var c = SomeAsyncClass()
c.doAsyncStuff()
以下是输出:

Queuing point 6
Queuing point 5
Queuing point 4
Point 6: Sleeping for: 3.0
Queuing point 3
Queuing point 2
Queuing point 1
Point 6: Awoken after: 3.0
Completed 6
Point 5: Sleeping for: 3.0
Point 5: Awoken after: 3.0
Completed 5
Point 4: Sleeping for: 3.0
Point 4: Awoken after: 3.0
Completed 4
Point 3: Sleeping for: 3.0
Point 3: Awoken after: 3.0
Completed 3
Point 2: Sleeping for: 3.0
Point 2: Awoken after: 3.0
Completed 2
Point 1: Sleeping for: 3.0
Point 1: Awoken after: 3.0
Completed 1
尽管如此,这并不是最好的方法。您最好使用为此目的而设计的iOS结构,即OperationQueue——它具有细粒度并发控制(
maxConcurrentOperationCount
),并且可以用作URLSession(
delegateQueue
)的基础。如果它适合您的需要,我建议您使用该结构