title: Apple Watch app: run an MKDirectionsRequest through the parent iOS app in the background?
body: <p>I'm writing an Apple Watch app and at some point I need to get an information about the walking or driving distance from the user's current location to a specific place.</p>
  
  <p>As recommended by Apple in its <a href="https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/WatchKitProgrammingGuide/DesigningaWatchKitApp.html#//apple_ref/doc/uid/TP40014969-CH3-SW5" rel="nofollow noreferrer" title="Apple Watch Programming Guide">Apple Watch Programming Guide</a>, I'm delegating all the hard work to the iOS app, by calling <code>openParentApplication</code> from the Apple Watch and implementing the <code>handleWatchKitExtensionRequest</code> function on the iOS app side. So, the iOS app is in charge of: 1) computing directions to the destination place using MapKit, and 2) returning the fetched distance and expected time to the Apple Watch.</p>
  
  <p>This operation is made through MapKit's <code>MKDirectionsRequest</code>, which tends to be "slow" (like, 1 or 2 seconds). If I test my code directly in the iOS app with the same arguments, everything works well: I get the expected time and distance response. However, from inside the Apple Watch app, the callback (<code>reply</code> parameter of <code>openParentApplication</code>) is never called and the device never gets its information back.</p>
  
  <p><strong>UPDATE 1:</strong> Replaced by update 3.</p>
  
  <p><strong>UPDATE 2:</strong> Actually, there is no timeout as I suspected in the beginning, but it only seems to work if the iOS app runs in foreground on the iPhone. If I try to run the query from the Apple Watch app without touching anything on the iPhone Simulator (i.e.: the app is woken up in the background), then nothing happens. As soon as I tap my app's icon on the iPhone Simulator, putting it frontmost, the Apple Watch receives the reply.</p>
  
  <p><strong>UPDATE 3:</strong> As requested by Duncan, below is the full code involved, with emphasis on where execution path is lost:</p>
  
  <p>(in class <code>WatchHelper</code>)</p>
  
  <pre><code>var callback: (([NSObject : AnyObject]!) -&gt; Void)?
  
  func handleWatchKitExtensionRequest(userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -&gt; Void)!) {
      // Create results and callback object for this request
      results = [NSObject: AnyObject]()
      callback = reply
      // Process request
      if let op = userInfo["op"] as String? {
          switch op {
          case AppHelper.getStationDistanceOp:
              if let uic = userInfo["uic"] as Int? {
                  if let transitType = userInfo["transit_type"] as Int? {
                      let transportType: MKDirectionsTransportType = ((transitType == WTTripTransitType.Car.rawValue) ? .Automobile : .Walking)
                      if let loc = DatabaseHelper.getStationLocationFromUIC(uic) {
                          // The following API call is asynchronous, so results and reply contexts have to be saved to allow the callback to get called later
                          LocationHelper.sharedInstance.delegate = self
                          LocationHelper.sharedInstance.routeFromCurrentLocationToLocation(loc, withTransportType: transportType)
                      }
                  }
              }
          case ... // Other switch cases here
          default:
              NSLog("Invalid operation specified: \(op)")
          }
      } else {
          NSLog("No operation specified")
      }
  }
  
  func didReceiveRouteToStation(distance: CLLocationDistance, expectedTime: NSTimeInterval) {
      // Route information has been been received, archive it and notify caller
      results!["results"] = ["distance": distance, "expectedTime": expectedTime]
      // Invoke the callback function with the received results
      callback!(results)
  }
  </code></pre>
  
  <p>(in class <code>LocationHelper</code>)</p>
  
  <pre><code>func routeFromCurrentLocationToLocation(destination: CLLocation, withTransportType transportType: MKDirectionsTransportType) {
      // Calculate directions using MapKit
      let currentLocation = MKMapItem.mapItemForCurrentLocation()
      var request = MKDirectionsRequest()
      request.setSource(currentLocation)
      request.setDestination(MKMapItem(placemark: MKPlacemark(coordinate: destination.coordinate, addressDictionary: nil)))
      request.requestsAlternateRoutes = false
      request.transportType = transportType
      let directions = MKDirections(request: request)
      directions.calculateDirectionsWithCompletionHandler({ (response, error) -&gt; Void in
          // This is the MapKit directions calculation completion handler
          // Problem is: execution never reaches this completion block when called from the Apple Watch app
          if response != nil {
              if response.routes.count &gt; 0 {
                  self.delegate?.didReceiveRouteToStation?(response.routes[0].distance, expectedTime: response.routes[0].expectedTravelTime)
              }
          }
      })
  }
  </code></pre>
  
  <p><strong>UPDATE 4</strong>: The iOS app is clearly setup to be able to receive location updates in the background, as seen in the screenshot below:</p>
  
  <p><img src="https://i.stack.imgur.com/W3b0x.png" alt="Location services are &quot;Always&quot; enabled for my app"></p>
  
  <p>So the question now becomes: is there any way to "force" an <code>MKDirectionsRequest</code> to happen in the background?</p>