// MARK: Radar Loop Methods
// Slow loop overlay with notification
@objc func slowRadarLoopwith(_ notification: NSNotification) {
DispatchQueue.main.async {
if (self.timeSlider.value) >= (self.timeSlider.minimumValue) && (self.timeSlider.value) <= (self.timeSlider.maximumValue)
{
DispatchQueue.main.async {
self.timeSlider.value = (self.timeSlider.value) + 1
}
self.timeSlider((self.timeSlider))
if self.timeSlider.value == self.timeSlider.maximumValue
{
// self?.timeSlider.value = 0
//self?.isPlaying = false
self.timer?.invalidate()
//self?.btnPlay.setImage(UIImage.init(named: "play"), for: .normal)
// DispatchQueue.main.async { self.dismissHUD( isAnimated: true ) }
self.isPlayLoopStarted = true
let nc = NotificationCenter.default
nc.removeObserver(self, name: Notification.Name("TileOverlayDownloaded"), object: nil)
self.perform(#selector(self.fastRadarLoop), with: nil, afterDelay: 3.0)
//self.fastRadarLoop()
}
}
else
{
// self?.timeSlider.value = 0
self.isPlaying = false
self.isPlayLoopStarted = false
self.timer?.invalidate()
self.btnPlay.setImage(UIImage.init(named: "play"), for: .normal)
DispatchQueue.main.async { self.dismissHUD( isAnimated: true ) }
}
}
}
// fast loop overlay with timer speed 0.4 sec
@objc func fastRadarLoop() {
DispatchQueue.main.async {
self.dismissHUD( isAnimated: true )
self.timeSlider.value = 0
self.timeSlider((self.timeSlider))
}
isRegionChanged = false
var isTimerStart = false
// self.timeSlider(self.timeSlider)
var loopTimeDelay: TimeInterval = 0.4
let zoom = Int(log2(360 * (Double(mapView.frame.size.width/256) / mapView.region.span.longitudeDelta)) + 1)
if DeviceType.IS_IPHONE_6
{
switch zoom {
case 0 ... 4:
loopTimeDelay = 0.5
case 5 ... 6:
loopTimeDelay = 0.6
case 7 ... 9:
loopTimeDelay = 0.7
case 10 ... 13:
loopTimeDelay = 0.8
default:
break
}
}
else
{
switch zoom {
case 0 ... 4:
loopTimeDelay = 0.4
case 5 ... 6:
loopTimeDelay = 0.5
case 7 ... 9:
loopTimeDelay = 0.6
case 10 ... 13:
loopTimeDelay = 0.7
default:
break
}
}
loopTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true, block: { (timer) in
if self.canExecuteLoop
{
self.canExecuteLoop = false
DispatchQueue.main.async {
timer.tolerance = 0.5
if (self.timeSlider.value) >= (self.timeSlider.minimumValue) && (self.timeSlider.value) <= (self.timeSlider.maximumValue)
{
if isTimerStart == false // timer moved to first value
{
isTimerStart = true
if self.timeSlider.value == self.timeSlider.minimumValue || self.timeSlider.value == self.timeSlider.maximumValue
{
self.timeSlider.value = 0
}
}
else
{
self.timeSlider.value = (self.timeSlider.value) + 1
}
/*
var arrTilerOverlay = self.mapView.overlays.filter { (overlay) -> Bool in
if overlay is PredictNowTileOverlay
{
return true
}
return false
}
if arrTilerOverlay.count>0
{
//arrTilerOverlay.remove(at: arrTilerOverlay.count-1)
DispatchQueue.main.async {
self.mapView.removeOverlays(arrTilerOverlay)
}
}*/
/*
if let _ = self.overlay
{
if (self.mapView.overlays.count)>1, let firstOverlay = self.mapView.overlays.first as? PredictNowTileOverlay
{
DispatchQueue.main.async {
self.mapView.removeOverlay(firstOverlay)
}
}
}*/
self.timeSlider((self.timeSlider))
if DeviceType.IS_IPHONE_6
{
self.perform(#selector(self.removePreviousOverlaysFromLoop), with: nil, afterDelay: 0.05)
}
else
{
self.perform(#selector(self.removePreviousOverlaysFromLoop), with: nil, afterDelay: 0.15) // called after 0.15 second delay so that it will remove tile after adding next tile so that it will not show flickering
}
if self.timeSlider.value == self.timeSlider.maximumValue // if time slider is at last position move to starting
{
isTimerStart = false
}
}
}
}
})
}
// removing previous tiles
@objc func removePreviousOverlaysFromLoop(){
DispatchQueue.main.async {
var arrTilerOverlay = self.mapView.overlays.filter { (overlay) -> Bool in
if overlay is PredictNowTileOverlay
{
return true
}
return false
}
if arrTilerOverlay.count>1
{
arrTilerOverlay.remove(at: arrTilerOverlay.count-1)
DispatchQueue.main.async {
self.mapView.removeOverlays(arrTilerOverlay)
}
}
}
}
Map tile overlay sub class
init(urlTemp: String?,strDateTime: String?, strProduct: String? ) {
super.init(urlTemplate: urlTemp)
//printLog(urlTemp)
//printLog(strDateTime)
timeForLoadingOverlay = strDateTime
product = strProduct
// arrlRequestedTiles.removeAll()
// arrResponseTiles.removeAll()
urlRequestCount = 0
postCount = 0
// urlRequestCount = 0
// urlResponseCount = 0
}
override func url(forTilePath path: MKTileOverlayPath) -> URL {
// printLog("current zoom is \(path.z)")
// printLog("requested tile\tz:\(path.z)\tx:\(path.x)\ty:\(path.y)")
let tilePath = URL.init(string: self.urlTemplate! + "/\(path.z)/\(path.x)/\(path.y).png?token=" + APITokens.allisonHouseAuthToken)
// https://tiler.allisonhouse.com/tile/{MODELID}/{PRODUCTID}/{RUNDATE}/{RUNTIME}/{VALIDDATE}/{VALIDTIME}/raw/{Z}/{Y}/{X}.png?token={TOKEN}
guard let tile = tilePath else {
// printLog("noTile")
return Bundle.main.url(
forResource: "parchment",
withExtension: "png",
subdirectory: "Tiles1",
localization: nil)!
}
// printLog(tile)
arrlRequestedTiles.append(tile)
urlRequestCount = urlRequestCount + 1
return tile
}
override func loadTile(at path: MKTileOverlayPath, result: @escaping (Data?, Error?) -> Void) {
// let path = Bundle.main.path(forResource: "11", ofType: "gif")!
// let data = try! Data(contentsOf: URL(fileURLWithPath: path))
// result(data, nil)
let tileUrl = url(forTilePath: path)
var request = URLRequest.init(url: tileUrl)
let session = URLSession.shared
let parentXFolderURL = URLForTilecacheFolder().appendingPathComponent(self.cacheXFolderNameForPath(path))
let tileFilePathURL = parentXFolderURL.appendingPathComponent(fileNameForTile(path))
let tileFilePath = tileFilePathURL.path
var useCachedVersion = false
if FileManager.default.fileExists(atPath: tileFilePath) {
if let fileAttributes = try? FileManager.default.attributesOfItem(atPath: tileFilePath),
let fileModificationDate = fileAttributes[FileAttributeKey.modificationDate] as? Date {
if fileModificationDate.timeIntervalSinceNow > -1.0 * maximumCacheAge {
useCachedVersion = true
}
}
}
if (useCachedVersion) {
arrResponseTiles.append(tileUrl)
// printLog("useCachedtile")
// autoreleasepool{
do
{
let cachedData = try Data(contentsOf: URL(fileURLWithPath: tileFilePath))
result(cachedData, nil)
}
catch let error{
printLog(error)
result(UIImage.init(named: "parchment")?.pngData(), error)
} // }
}
else
{
request.timeoutInterval = 120
Alamofire.request(request).responseData { (response) in
if let url = response.request?.url
{
self.arrResponseTiles.append(url)
}
guard let responseData = response.result.value else{return}
// self.urlResponseCount = self.urlResponseCount + 1
if response.result.isSuccess
{
do {
try FileManager.default.createDirectory(at: parentXFolderURL,
withIntermediateDirectories: true,
attributes: nil)
try responseData.write(to: URL(fileURLWithPath: tileFilePath),
options: [.atomic])
} catch let error {
printLog(error)
}
// printLog("downloadedtile")
// printLog(responseData.count)
result(responseData, response.result.error as NSError?)
}
else
{
// result(UIImage.init(named: "parchment")?.pngData(), response.result.error)
result(nil,response.result.error)
}
// serviceGroup.leave()
}
// serviceGroup.notify(queue: DispatchQueue.main) {
// // downloaded
//
// printLog("PostNotifiation for searvceGroup downloaded for tiles in current region")
// }
}
}
Я реализовал код для добавления наложения для данных метеорологического радара на карту, и я пытаюсь реализовать зацикливание этих наложений радара в 12 различных временных интервалах, чтобы это выглядело как эффект анимации, вот мой код. я использовал подкласс mktileoverlay для loadtile на пути