Это было немного сложно для приложения, над которым я работаю, поскольку есть много вызовов для загрузки набора плиток карт для нескольких уровней масштабирования, поэтому приведенный ниже код может быть немного сложнее, чем вам нужно (но показывает что очереди работают для моментальной съемки). Например, мне понадобился файл dispatchSemaphore, чтобы избежать очередей сотен или тысяч одновременных снимков - это ограничивает их примерно до 25 одновременных снимков, захваченных в потоке.
Кроме того, я делаю это в Swift 3, поэтому в GCD могут быть изменения, которые позволяют мне делать это, представляя проблемы для вас.
Логика здесь заключается в том, чтобы получить все запросы, запущенные в processQueue, в то время как основная очередь остается разблокированной, поэтому пользовательский интерфейс остается активным. Затем, как только до 25 запросов проходят через ворота семафора в любой момент времени, они вводят snapshotQueue через вызов snapshotter.start. Когда один снимок заканчивается, другой запускается до тех пор, пока processQueue не будет пустым.
unowned let myself = self // Avoid captures in closure
let processQueue = DispatchQueue(label: "processQueue", qos: .userInitiated)
let snapshotQueue = DispatchQueue(label: "snapshotQueue")
var getSnapshotter = DispatchSemaphore(value: 25)
processQueue.async
{
var centerpoint = CLLocationCoordinate2D()
centerpoint.latitude = (topRight.latitude + bottomLeft.latitude)/2.0
centerpoint.longitude = (topRight.longitude + bottomLeft.longitude)/2.0
let latitudeDelta = abs(topRight.latitude - bottomLeft.latitude)
let longitudeDelta = abs(topRight.longitude - bottomLeft.longitude)
let mapSpan = MKCoordinateSpanMake(latitudeDelta, longitudeDelta)
var mapRegion = MKCoordinateRegion()
mapRegion.center = centerpoint
mapRegion.span = mapSpan
let options = MKMapSnapshotOptions()
options.region = mapRegion
options.mapType = .standard
options.scale = 1.0
options.size = CGSize(width: 256, height: 256)
myself.getSnapshotter.wait() // Limit the number of concurrent snapshotters since we could invoke very many
let snapshotter = MKMapSnapshotter(options: options)
snapshotter.start(with: myself.snapshotQueue, completionHandler: {snapshot, error in
if error == nil
{
self.saveTile(path: path, tile: snapshot!.image, z: z, x: x, y: y)
// saveTile writes the image out to a file in the mapOverlay file scheme
} else {
print("Error Creating Map Tile: ", error!)
}
if myself.getSnapshotter.signal() == 0
{
// show status as completed (though could be up to 20 snapshots finishing, won't take long at this point
}
})
}
Это работает для меня в получении до 5K снимков для создания 7-масштабирования карты уровня автономного образа в набор без блокировки пользовательского интерфейса, так что я очень комфортно с кодом.
Что касается необходимости находиться на переднем плане, это правильно, поэтому я использую команду: [UIApplication.shared.isIdleTimerDisabled = true]. Просто убедитесь, что он установлен на false, как только вы закончите. –
Ничего себе, выглядит впечатляюще. Я не очень хорошо знаком с продвинутой очередью. Может потребоваться некоторое время, чтобы попробовать какую-то форму этого решения. – TealShift
Это разочаровывает передний план, так как я вытягиваю данные тренировки из Apple Watch, и единственная остановка bg-обработки - эта немая функция. :/ – TealShift