Dictionary Becomes Nil When Trying to Pass Back Cllocation Object to iOS App Extension

Dictionary becomes nil when trying to pass back CLLocation object to iOS app extension

I read in the docs: "The contents of the dictionary must be serializable to a property list file." But a CLLocation is not serializable in this way. Presumably you must wrap it up (again) in an NSData before you stick it into the dictionary to be passed across the barrier.

Apple Watch app: run an MKDirectionsRequest through the parent iOS app in the background?

This code works in an app that I am working on. It also works with the app in the background so I think it's safe to say that MKDirectionsRequest will work in background mode. Also, this is called from the AppDelegate and is wrapped in a beginBackgroundTaskWithName tag.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

MKPlacemark *destPlacemark = [[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(destLat, destLon) addressDictionary:nil];
MKPlacemark *currentPlacemark = [[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(currLat, currLon) addressDictionary:nil];

NSMutableDictionary __block *routeDict=[NSMutableDictionary dictionary];
MKRoute __block *routeDetails=nil;

MKDirectionsRequest *directionsRequest = [[MKDirectionsRequest alloc] init];
[directionsRequest setSource:[[MKMapItem alloc] initWithPlacemark:currentPlacemark]];
[directionsRequest setDestination:[[MKMapItem alloc] initWithPlacemark:destPlacemark]];
directionsRequest.transportType = MKDirectionsTransportTypeAutomobile;

dispatch_async(dispatch_get_main_queue(), ^(){

MKDirections *directions = [[MKDirections alloc] initWithRequest:directionsRequest];

[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(@"Error %@", error.description);

} else {
NSLog(@"ROUTE: %@",response.routes.firstObject);
routeDetails = response.routes.firstObject;

[routeDict setObject:[NSString stringWithFormat:@"%f",routeDetails.distance] forKey:@"routeDistance"];
[routeDict setObject:[NSString stringWithFormat:@"%f",routeDetails.expectedTravelTime] forKey:@"routeTravelTime"];

NSLog(@"Return Dictionary: %@",routeDict);

reply(routeDict);
}
}];

});
});

EDIT from OP: The code above probably works in ObjC, but the exact reason why it works is that it is not using MKMapItem.mapItemForCurrentLocation(). So the working code for me looks as follows:

func routeFromCurrentLocationToLocation(destination: CLLocation, withTransportType transportType: MKDirectionsTransportType) {
// Calculate directions using MapKit
let currentLocation = MKMapItem(placemark: MKPlacemark(coordinate: CLLocationCoordinate2DMake(lat, lng), addressDictionary: nil))
var request = MKDirectionsRequest()
// ...
}

Mapping to Swift Object issue showing nil using Alamofire ObjectMapper

i think you are missing the right documentation of ObjectMapper lib.
Check this Github ObjectMapper.

These are the types supported by the lib:

  • Int
  • Bool
  • Double
  • Float
  • String
  • RawRepresentable (Enums)
  • Array<AnyObject>
  • Dictionary<String, AnyObject>
  • Object<T: Mappable>
  • Array<T: Mappable>
  • Array<Array<T: Mappable>>
  • Set<T: Mappable>
  • Dictionary<String, T: Mappable>
  • Dictionary<String, Array<T:Mappable>>
  • Optionals of all the above
  • Implicitly Unwrapped Optionals of the above

So, if you are trying to map an Object not in that list, the result is nil.

In your case is var location: CLLocation?.

If you need to map CLLocation Object, one way is to map a CustomCLLocation with all properties as follows:
JSON(i don't know your Json, this is an example)

"location":{
"long": 43.666,
"lat": 73.4
}

Swift: create another file "CustomCLLocation" for example like the first one but for mapping CLLocation with your Json

var latitude: Double?
var longitude: Double?

required init?(_ map: Map) {
mapping(map)

}
func mapping(map: Map) {

longitude <- map["long"]
latitude <- map["lat"]
}

and now, you can map an "fake" CLLocation Object:
var location: CustomCLLocation?

Then if you want a really CLLocation. just create an Simply Extension like that(add it in the CustomCLLocation file):

extension CLLocation {
public class func createFromCustomCLLocation(custom: CustomCLLocation) -> CLLocation {
return self.init(custom.latitude,custom.longitude)
}
}

Using the conversion:

var locationCLL = CLLocation.createFromCustomCLLocation(location) // now is a CLLocation

Edited: Alamofire Request

I have the same request on my app with the last version of AlamofireObjectMapper for ios 8.0 +

Alamofire.request(.GET, UrlEndpoints.branchUrl()).responseArray { (response: [BranchObjectMapper]?, error : ErrorType?) in
if(error != nil) {
print(error)
}else{
print("data downloaded")

if let response = response {
branchList(response)
for branch in self.branchList {
print(branch.id)
print(branch.name)
}
}
}
}

How to retrieve user's current city name?

What you have to do is setup a CLLocationManager that will find your current coordinates. With the current coordinates you need to use MKReverseGeoCoder to find your location.

- (void)viewDidLoad 
{
// this creates the CCLocationManager that will find your current location
CLLocationManager *locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[locationManager startUpdatingLocation];
}

// this delegate is called when the app successfully finds your current location
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// this creates a MKReverseGeocoder to find a placemark using the found coordinates
MKReverseGeocoder *geoCoder = [[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate];
geoCoder.delegate = self;
[geoCoder start];
}

// this delegate method is called if an error occurs in locating your current location
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"locationManager:%@ didFailWithError:%@", manager, error);
}

// this delegate is called when the reverseGeocoder finds a placemark
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
MKPlacemark * myPlacemark = placemark;
// with the placemark you can now retrieve the city name
NSString *city = [myPlacemark.addressDictionary objectForKey:(NSString*) kABPersonAddressCityKey];
}

// this delegate is called when the reversegeocoder fails to find a placemark
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
NSLog(@"reverseGeocoder:%@ didFailWithError:%@", geocoder, error);
}

Swift 5 API call data variable nil but API proved working

The solution Postman generated works for me:

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

var semaphore = DispatchSemaphore (value: 0)

var request = URLRequest(url: URL(string: "http://a542cd3116ed.ngrok.io/api/v1/public/location/66.68994/10.249066/50")!,timeoutInterval: Double.infinity)
request.httpMethod = "GET"

let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
semaphore.signal()
return
}
print(String(data: data, encoding: .utf8)!)
semaphore.signal()
}

task.resume()
semaphore.wait()


Related Topics



Leave a reply



Submit