Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.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_Asynchronous_Mklocalsearchrequest - Fatal编程技术网

Swift 同步进行多个地图局部搜索

Swift 同步进行多个地图局部搜索,swift,asynchronous,mklocalsearchrequest,Swift,Asynchronous,Mklocalsearchrequest,我尝试同步进行多个搜索(我的意思是一个接一个,在运行下一个请求之前等待上一个请求完成),并阻塞,直到所有操作完成后再继续 但本地搜索的完成句柄看起来像被阻止了,一旦信号量放弃,它就会运行。我多次尝试都没有成功 我的代码和日志如下(您可以复制/粘贴到游乐场): [更新] 预期输出应在最后一行显示无***警告和全部完成,如下所示(编号的确切顺序取决于网络条件): [更新2]取消注释行时输出的值//queue.maxConcurrentOperationCount=1 搜索(:in:centered:

我尝试同步进行多个搜索(我的意思是一个接一个,在运行下一个请求之前等待上一个请求完成),并阻塞,直到所有操作完成后再继续

但本地搜索的完成句柄看起来像被阻止了,一旦信号量放弃,它就会运行。我多次尝试都没有成功

我的代码和日志如下(您可以复制/粘贴到游乐场):

[更新]

预期输出应在最后一行显示无
***警告
全部完成
,如下所示(编号的确切顺序取决于网络条件):

[更新2]取消注释行时输出的值
//queue.maxConcurrentOperationCount=1

搜索(:in:centered:id:):第0部分的本地搜索2020-03-28 23:49:41+0000 搜索(:in:centered:id:):等待第0部分完成2020-03-28 23:49:41+0000 搜索(:in:centered:id:):***警告:第0次超时,作业未完成2020-03-28 23:49:46+0000 搜索(:in:centered:id:):第1部分的本地搜索2020-03-28 23:49:46+0000 搜索(:in:centered:id:):等待第1部分完成2020-03-28 23:49:46+0000 搜索(:in:centered:id:):***警告:第1次超时,作业未完成2020-03-28 23:49:51+0000 搜索(:in:centered:id:):第二部分的本地搜索2020-03-28 23:49:51+0000 搜索(:in:centered:id:):等待第2部分完成2020-03-28 23:49:51+0000 搜索(:in:centered:id:):***警告:第2次超时,作业未完成2020-03-28 23:49:56+0000 搜索(:in:centered:id:):第三部分的本地搜索2020-03-28 23:49:56+0000 搜索(:in:centered:id:):等待第三部分完成2020-03-28 23:49:56+0000 搜索(:in:centered:id:):***警告:第三次超时,作业未完成2020-03-28 23:50:01+0000 全部完成2020-03-2823:50:01+0000 0获得可选(10)项2020-03-28 23:50:02+0000 3个可选(10)项2020-03-28 23:50:02+0000 2个可选(10)项2020-03-28 23:50:02+0000 1个可选(10)项2020-03-28 23:50:02+0000


注意:顺便说一句,我还在每次打印的末尾添加了
\(Date())

如果您希望这些操作以串行方式运行,则必须指定队列一次只能运行一个,例如

queue.maxConcurrentOperationCount = 1
而且,正如您所发现的,您希望避免使用
addOperations
waitUntilFinished
选项,因为这会在操作完成之前阻塞当前线程。相反,使用完成处理程序模式


以下是我使用的代码:

func performMultipleSearches(completion: @escaping () -> Void) {
    let searches = ["restaurant", "coffee", "hospital", "natural history museum"]

    let queue = OperationQueue()
    queue.maxConcurrentOperationCount = 1

    for (i, searchText) in searches.enumerated() {
        queue.addOperation {
            self.search(searchText, in: self.mapView.region, id: i)
        }
    }

    queue.addOperation {
        completion()
    }
}

func search(_ query: String, in region: MKCoordinateRegion, id: Int) {
    let semaphore = DispatchSemaphore(value: 0)

    os_log("%d starting", id)

    let request = MKLocalSearch.Request()
    request.naturalLanguageQuery = query
    request.region = region

    if #available(iOS 13, *) {
        request.resultTypes = .pointOfInterest
    }

    let search = MKLocalSearch(request: request)

    search.start { response, error in
        defer { semaphore.signal() }

        guard let mapItems = response?.mapItems else {
            os_log("  %d failed", id)
            return
        }

        os_log("  %d succeeded, found %d:", id, mapItems.count)
    }

    os_log("  %d waiting", id)
    guard semaphore.wait(timeout: .now() + 5) == .success else {
        os_log("  %d timedout", id)
        return
    }

    os_log("  %d done", id)
}
这产生了:

2020-03-28 16:16:25.219565-0700 MyApp[46601:2107182] 0 starting
2020-03-28 16:16:25.220018-0700 MyApp[46601:2107182]   0 waiting
2020-03-28 16:16:25.438121-0700 MyApp[46601:2107033]   0 succeeded, found 10:
2020-03-28 16:16:25.438269-0700 MyApp[46601:2107182]   0 done
2020-03-28 16:16:25.438436-0700 MyApp[46601:2107182] 1 starting
2020-03-28 16:16:25.438566-0700 MyApp[46601:2107182]   1 waiting
2020-03-28 16:16:25.639198-0700 MyApp[46601:2107033]   1 succeeded, found 10:
2020-03-28 16:16:25.639357-0700 MyApp[46601:2107182]   1 done
2020-03-28 16:16:25.639490-0700 MyApp[46601:2107182] 2 starting
2020-03-28 16:16:25.639598-0700 MyApp[46601:2107182]   2 waiting
2020-03-28 16:16:25.822085-0700 MyApp[46601:2107033]   2 succeeded, found 10:
2020-03-28 16:16:25.822274-0700 MyApp[46601:2107182]   2 done
2020-03-28 16:16:25.822422-0700 MyApp[46601:2107162] 3 starting
2020-03-28 16:16:25.822567-0700 MyApp[46601:2107162]   3 waiting
2020-03-28 16:16:26.015566-0700 MyApp[46601:2107033]   3 succeeded, found 1:
2020-03-28 16:16:26.015696-0700 MyApp[46601:2107162]   3 done
2020-03-28 16:16:26.015840-0700 MyApp[46601:2107162] all done

无论如何,我不会使用信号量,而是使用异步
操作
子类。例如,您可以使用
异步操作
类,然后执行以下操作:

class SearchOperation: AsynchronousOperation {
    let identifier: Int
    let searchText: String
    let region: MKCoordinateRegion

    init(identifier: Int, searchText: String, region: MKCoordinateRegion) {
        self.identifier = identifier
        self.searchText = searchText
        self.region = region

        super.init()
    }

    override func main() {
        os_log("%d started", identifier)

        let request = MKLocalSearch.Request()
        request.naturalLanguageQuery = searchText
        request.region = region

        if #available(iOS 13, *) {
            request.resultTypes = .pointOfInterest
        }

        let search = MKLocalSearch(request: request)

        search.start { response, error in
            defer { self.finish() }

            guard let mapItems = response?.mapItems else {
                os_log("  %d failed", self.identifier)
                return
            }

            os_log("  %d succeeded, found %d:", self.identifier, mapItems.count)
        }
    }
}
然后

let searches = ["restaurant", "coffee", "hospital", "natural history museum"]

let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1

for (i, searchText) in searches.enumerated() {
    queue.addOperation(SearchOperation(identifier: i, searchText: searchText, region: mapView.region))
}

queue.addOperation {
    completion()
}

如果希望这些操作以串行方式运行,则必须指定队列一次只能运行一个,例如

queue.maxConcurrentOperationCount = 1
而且,正如您所发现的,您希望避免使用
addOperations
waitUntilFinished
选项,因为这会在操作完成之前阻塞当前线程。相反,使用完成处理程序模式


以下是我使用的代码:

func performMultipleSearches(completion: @escaping () -> Void) {
    let searches = ["restaurant", "coffee", "hospital", "natural history museum"]

    let queue = OperationQueue()
    queue.maxConcurrentOperationCount = 1

    for (i, searchText) in searches.enumerated() {
        queue.addOperation {
            self.search(searchText, in: self.mapView.region, id: i)
        }
    }

    queue.addOperation {
        completion()
    }
}

func search(_ query: String, in region: MKCoordinateRegion, id: Int) {
    let semaphore = DispatchSemaphore(value: 0)

    os_log("%d starting", id)

    let request = MKLocalSearch.Request()
    request.naturalLanguageQuery = query
    request.region = region

    if #available(iOS 13, *) {
        request.resultTypes = .pointOfInterest
    }

    let search = MKLocalSearch(request: request)

    search.start { response, error in
        defer { semaphore.signal() }

        guard let mapItems = response?.mapItems else {
            os_log("  %d failed", id)
            return
        }

        os_log("  %d succeeded, found %d:", id, mapItems.count)
    }

    os_log("  %d waiting", id)
    guard semaphore.wait(timeout: .now() + 5) == .success else {
        os_log("  %d timedout", id)
        return
    }

    os_log("  %d done", id)
}
这产生了:

2020-03-28 16:16:25.219565-0700 MyApp[46601:2107182] 0 starting
2020-03-28 16:16:25.220018-0700 MyApp[46601:2107182]   0 waiting
2020-03-28 16:16:25.438121-0700 MyApp[46601:2107033]   0 succeeded, found 10:
2020-03-28 16:16:25.438269-0700 MyApp[46601:2107182]   0 done
2020-03-28 16:16:25.438436-0700 MyApp[46601:2107182] 1 starting
2020-03-28 16:16:25.438566-0700 MyApp[46601:2107182]   1 waiting
2020-03-28 16:16:25.639198-0700 MyApp[46601:2107033]   1 succeeded, found 10:
2020-03-28 16:16:25.639357-0700 MyApp[46601:2107182]   1 done
2020-03-28 16:16:25.639490-0700 MyApp[46601:2107182] 2 starting
2020-03-28 16:16:25.639598-0700 MyApp[46601:2107182]   2 waiting
2020-03-28 16:16:25.822085-0700 MyApp[46601:2107033]   2 succeeded, found 10:
2020-03-28 16:16:25.822274-0700 MyApp[46601:2107182]   2 done
2020-03-28 16:16:25.822422-0700 MyApp[46601:2107162] 3 starting
2020-03-28 16:16:25.822567-0700 MyApp[46601:2107162]   3 waiting
2020-03-28 16:16:26.015566-0700 MyApp[46601:2107033]   3 succeeded, found 1:
2020-03-28 16:16:26.015696-0700 MyApp[46601:2107162]   3 done
2020-03-28 16:16:26.015840-0700 MyApp[46601:2107162] all done

无论如何,我不会使用信号量,而是使用异步
操作
子类。例如,您可以使用
异步操作
类,然后执行以下操作:

class SearchOperation: AsynchronousOperation {
    let identifier: Int
    let searchText: String
    let region: MKCoordinateRegion

    init(identifier: Int, searchText: String, region: MKCoordinateRegion) {
        self.identifier = identifier
        self.searchText = searchText
        self.region = region

        super.init()
    }

    override func main() {
        os_log("%d started", identifier)

        let request = MKLocalSearch.Request()
        request.naturalLanguageQuery = searchText
        request.region = region

        if #available(iOS 13, *) {
            request.resultTypes = .pointOfInterest
        }

        let search = MKLocalSearch(request: request)

        search.start { response, error in
            defer { self.finish() }

            guard let mapItems = response?.mapItems else {
                os_log("  %d failed", self.identifier)
                return
            }

            os_log("  %d succeeded, found %d:", self.identifier, mapItems.count)
        }
    }
}
然后

let searches = ["restaurant", "coffee", "hospital", "natural history museum"]

let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1

for (i, searchText) in searches.enumerated() {
    queue.addOperation(SearchOperation(identifier: i, searchText: searchText, region: mapView.region))
}

queue.addOperation {
    completion()
}

我已经试过了(参见代码中的注释)。对我来说,这就像在search.start()中阻止了趋势一样,因为在信号量过期之前,永远不会触发完成闭包(应该在主线程上运行)。在操场上试一试。使用
maxConcurrentOperationCount
set对我来说效果很好。我更新了预期结果,以便更清楚地获得什么,并用我的输出更新了我的结果。但是,
maxConcurrentOperationCount=1
是必需的。否则,它将同时运行它们。对我来说,这就像在search.start()中阻止了趋势一样,因为在信号量过期之前,永远不会触发完成闭包(应该在主线程上运行)。在操场上试一试。使用
maxConcurrentOperationCount
set对我来说效果很好。我更新了预期结果,以便更清楚地获得什么,并用我的输出更新了我的结果。但是,
maxConcurrentOperationCount=1
是必需的。否则,它将同时运行它们。但是,如果您使用
maxConcurrentOperationCount=1
(这对于不同时运行搜索非常重要),那么预期的结果就不应该是这样的。在上一次搜索完成之前,您不应该看到开始下一次搜索。我已在取消注释max=1时使用输出进行了更新,以便查看。我正在查看你的代码:情况不同。在您的中,您可以进行不同的查询。在我的世界里,只有地区在变化。因此,我正在进行更改,以查看eta的行为是否相同。是的,既然您使用了max=1,那么您将看到您的输出是有序的,这是完全有意义的。唯一让人好奇的是他们为什么要超时。你是否在应用程序中而不是在游乐场中尝试过这一点?你试过把你的超时时间从5秒增加到更大的吗?是的,这是最初的点。为什么会超时。在真实设备上也是如此。如果我设置了长时间的超时,同样的行为。通过删除设置waitUntilFinished:false,超时消失了。但是,我当然失去了我的障碍。你列出了你期望的结果。但是,如果您使用
maxConcurrentOperationCount=1
(这对于不同时运行搜索非常重要),那么预期的结果就不应该是这样的。在上一次搜索完成之前,您不应该看到启动下一次搜索