title: iOS MKMapView loading custom tile optimisation
body: <p>I have developed iOS Map application with custom TileOverlay, which loads tiles from our own server. I extended TileOverlay class, which gets tile data as following:</p>
  
  <pre><code>override func loadTile(at path: MKTileOverlayPath, result: @escaping (Data?, Error?) -&gt; Void)
  {
      let url = self.url(forTilePath: path)
      if let cachedData = cache.object(forKey: url as AnyObject) as? NSData
      {
          result(cachedData as Data, nil)
      } else {
  
          let session = URLSession.shared
          let request = NSURLRequest(url: url)
          let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -&gt; Void in
  
              if let data = data {
                  self.cache.setObject(data as AnyObject, forKey: url as AnyObject)
              }
              result(data, error)
          })
          task.resume()
      }
  }
  </code></pre>
  
  <p>The app works normally, but when I zoom in/out fast or pan to random directions, then tiles are loading very slowly. Especially in iPad it takes about a minute to load current view. I added print(path.z) to the method <code>"loadTile"</code> and realised that mapView requests tiles which is not in the selected area. In the result the selected area is loading very slowly. I put <code>if</code> condition to the thread execute block</p>
  
  <pre><code>        let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -&gt; Void in
  
          **let zoomLevel = self.getZoom()
          if  Double(path.z)  &lt; zoomLevel - 2  || Double(path.z) &gt; zoomLevel + 2 {
              print("cancelled by zoom")
              return
          }**
          if let data = data {
              self.cache.setObject(data as AnyObject, forKey: url as AnyObject)
          }
          result(data, error)
          print("")
      })
      task.resume()
  </code></pre>
  
  <p>It enhanced loading tiles several times, but when loading finishes, there are blank tiles. It's because zoom level is not calculated correctly (I have found several methods to find zoom level, but none of them are definite for this issue).</p>
  
  <p>I'm using MapKit sdk and the version of Swift is 3.0</p>
  
  <p>So my question is, how to optimize tile loading process? How to cancel unnecessary threads? Any suggestions for this kind of issue. Thanks in advance.</p>