Location Services not returning close places - ios

I'm using a code which I will post after this to return the closest places based on what the user types in a UITextField using a natural language query. I store all the places in an array and that pass that array to the next scene (a UITableViewController) in prepareForSegue. Than I use the array to load all the places. On the simulator, it shows all the default locations that Apple has which makes sense. But then, I test it out on a real iPhone and despite enabling location services for the app, I still get default locations. I tried again and again but I could not get actual results. It worked once a few weeks ago, but since then it has stopped. Any ideas? Here is the code:
- (void) performSearch {
NSLog(_searchLabel.text);
MKLocalSearchRequest *request =
[[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = _searchLabel.text;
_foundPlaces = [[NSMutableArray alloc] init];
_foundPlacesD = [[NSMutableArray alloc]init];
//NSLog(_place);
MKLocalSearch *search =
[[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
if (response.mapItems.count == 0)
NSLog(#"No Matches");
else{
for (MKMapItem *item in response.mapItems)
{
NSString *n = item.name;
[_foundPlaces addObject:n];
NSLog(n);
MKDirectionsRequest *dr = [MKDirectionsRequest new];
MKMapItem *source = [MKMapItem mapItemForCurrentLocation];
[dr setSource:source];
[dr setDestination:item];
MKDirections *directions = [[MKDirections alloc]initWithRequest:dr];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *mresponse, NSError *error) {
if(mresponse.routes.count == 0){
NSLog(#"No routes");
}
else{
for(MKRoute *route in mresponse.routes){
CLLocationDistance d = route.distance/1000;
NSString *dText = [NSString stringWithFormat:#"%g kilometers", d];
[_foundPlacesD addObject:dText];
NSLog(dText);
}
}
}];
}
[self performSegueWithIdentifier:#"locationResults" sender:self];
}
}];
}

I believe I fixed it. The error was that the segue was being performed outside the completion, when it should be performed inside.

Related

MapView: Tapping annotation gives me wrong detail view data?

I'm using an NSDictionary to populate data for my MapView annotations. However, when I tap on my MapView annotation, the detailView should display the selected user's information. That said, right now, when I tap an annotation, all detailViews display the same user's information (even though the details in the actual annotation's display bubble are correct). How can I fix this? Why won't NSDictionary allow me to do this?
MapViewController.m
NSMutableDictionary *viewParams = [NSMutableDictionary new];
[viewParams setValue:#"u000" forKey:#"view_name"];
[DIOSView viewGet:viewParams success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.addressData = [responseObject mutableCopy];
for (NSMutableDictionary *multiplelocations in self.addressData) {
NSString *location = multiplelocations[#"street_address"];
NSLog(#"Pull addresses %#", location);
NSString *userNames = multiplelocations[#"users_name"];
NSString *userBio = multiplelocations[#"userbio"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 8.0;
region.span.latitudeDelta /= 8.0;
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = placemark.coordinate;
point.title = userNames;
point.subtitle = userBio;
[self.mapView addAnnotation:point];
}
}
];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
}
-(void)calloutTapped:(UITapGestureRecognizer *) sender
{
NSLog(#"Callout was tapped");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
OtherUserViewController *yourViewController = (OtherUserViewController *)[storyboard instantiateViewControllerWithIdentifier:#"OtherUserViewController"];
NSDictionary *dictionary = [[NSDictionary alloc] init];
dictionary = [[self.addressData firstObject] mutableCopy];
yourViewController.mapuserData = dictionary;
[self.navigationController pushViewController:yourViewController animated:YES];
}
self.addressData via console
{
address = "1300 Fake Street, Vancouver, BC";
childrenunder = No;
city = Va;
"emergency facility" = Yes;
"first name" = Admin;
"last name" = Account;
phone = "Not Available";
"photo_path" = "http://myurl.com/files/stored/1461176121.jpg";
"postal code" = V6B0L1;
"profile photo" = "<img typeof=\"foaf:Image\" src=\"stored/1461176121.jpg\" width=\"300\" height=\"300\" alt=\"\" />";
"property type" = House;
province = B;
"street_address" = "1300 Fake Street, Vancouver, BC";
supervision = Yes;
uid = 1;
userbio = "Need assistance? This account belongs to the team! Message us if you have any questions.";
"users_name" = Britt;
}
)
dictionary = [[self.addressData firstObject] mutableCopy];
Are you serious?
This should be
NSMutableDictionary *dictionary = [self.addressData mutableCopy];
While navigating to detail view controller, you are always getting the first object from the dictionary array.
[[self.addressData firstObject] mutableCopy];
Thats the reason you are getting the same information for all the annotation view.
Instead of that line of code, You have to identify which map marker is clicked on the MapView, for example identify the index of the dictionary array. Pick the dictionary from the array and pass it to the detail view.

How to cancel a completion handler in iOS

I want to get an array of nearby locations using mapkit framework. So when the user types in a textfield I call the following function.
- (void)searchForLocations:(NSString *)string
{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(search:) object:nil];
[self performSelectorInBackground:#selector(search:) withObject:string];
}
- (void)search :(NSString *)string
{
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = string;
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.05;
region.span = span;
region.center = newLocation.coordinate;
request.region = region;
MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
if (response.mapItems.count == 0)
{
NSLog(#"No Matches");
}
else
{
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
}
}];
}
As you can see I want to cancel the previous search if a new input text is coming. But the previous search is not cancelled. How can i cancel the previous search?
Thanks in advance.
There is a cancel method on MKLocalSearch. Have you tried that one?
Edit: Ah, sorry, I was being stupid. You need to keep a reference to your old search in some way in order to cancel it. Put it in a property which you can clear (i.e. set to nil) when the search is finished. Whenever you call the search function, cancel the previous search function (no "if" needed, nil swallows all), then create a new one
#property (nonatiomic, strong) MKLocalSearch *previousSearch;
- (void)search :(NSString *)string
{
[self.previousSearch cancel];
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = string;
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.05;
region.span = span;
region.center = newLocation.coordinate;
request.region = region;
MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
self.previousSearch = nil;
if (response.mapItems.count == 0)
{
NSLog(#"No Matches");
}
else
{
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
}
}];
self.previousSearch = search;
}
The MKLocalSearch object has a cancel method that you can use to cancel a pending search. You can't simply cancel the selector as you are trying to do as that selector will complete very quickly, with the MKLocalSearch dispatched in the background.
You will need a property to store your search object, so that you can tell if it is still searching and cancel the search if required.
#property (strong,nonatomic) MKLocalSearch *localSearch;
- (void)search :(NSString *)string
{
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = string;
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.05;
region.span = span;
region.center = newLocation.coordinate;
request.region = region;
if (self.localSearch!=nil) {
if (self.localSearch.searching) {
[self.localSearch cancel];
self.localSearch=nil;
}
}
self.localSearch = [[MKLocalSearch alloc]initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
if (response.mapItems.count == 0)
{
NSLog(#"No Matches");
}
else
{
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
}
}];
}
Well you can use NSBlockOperation.
Suppose the global variable that you have used for NSBlockOperation is blockOperation. Then :
[search startWithCompletionHandler:^(MKLocalSearchResponse
*response, NSError *error) {
blockOperation = NSBlockOperation(block: { () -> Void in
if (response.mapItems.count == 0) {
NSLog(#"No Matches");
} else {
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
}
})
}];
Then you can use this blockOperation to cancel wherever you want as follows:
blockOperation.cancel()

Get MKLocalSearch to only return places

I have looked at the documentation and can't find a way to use MKLocalSearch to only return areas. For example I want the search to search world wide for cities, towns, villages & counties but not return any businesses or hotels etc. Is that possible?
Thanks
D
I think you can use predicate like this:
NSPredicate *noBusiness = [NSPredicate predicateWithFormat:#"business.uID == 0"];
NSMutableArray *itemsWithoutBusinesses = [response.mapItems mutableCopy];
[itemsWithoutBusinesses filterUsingPredicate:noBusiness];
Example local search code is also adding, which will solve your problem.
-(void)issueLocalSearchLookup:(NSString *)searchString {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.location.coordinate, 30000, 30000);
self.localSearchRequest = [[MKLocalSearchRequest alloc] init];
self.localSearchRequest.region = region;
self.localSearchRequest.naturalLanguageQuery = searchString;
self.localSearch = [[MKLocalSearch alloc] initWithRequest:self.localSearchRequest];
[self.localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if(error){
NSLog(#"LocalSearch failed with error: %#", error);
return;
} else {
for(MKMapItem *mapItem in response.mapItems){
[self.data addObject:mapItem];
}
[self.searchDisplayController.searchResultsTableView reloadData];
}
}];
}
based on your requirement change the key parameter for addressDictionary.
for(MKMapItem *mapItem in response.mapItems)
{
NSLog(#"%#",mapItem.placemark.addressDictionary[#"Street"]);
}

UITableView with complex cells is slow and laggy

I've almost finished my app and everything seems to work but the main view.
It's an UIViewController with an embedded UITableView.
I'm using Parse as the backend, and I get an array of the objects I need in my viewDidLoad method.
Each cell contains some data that I'm fetching in the tableView:cellForRowAtIndexPath and I'm afraid that this is the reason why my table view is so laggy, but I don't know how to fetch the data I need for each object in my array without having the indexPath.row number.
I've already made each cell element "opaque" as suggested in other answers.
This is my code, any help would be greatly appreciated:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cellHT";
CellHT *cell = (CellHT *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[CellHT alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// self.hH is an NSArray containing all the objects
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
cell.lblTitle.text = [self.hH[indexPath.row] objectForKey:#"title"];
cell.lblVenueName.text = [self.hH[indexPath.row] objectForKey:#"venueName"];
cell.lblDistance.text = NSLocalizedString(#"Distance from you", nil);
self.geo = [self.hH[indexPath.row] objectForKey:#"coordinates"];
// the formatters are initialized in the viewDidLoad: method
self.formatData = [NSDateFormatter dateFormatFromTemplate:#"dd/MM" options:0 locale:[NSLocale currentLocale]];
[self.formatterData setDateFormat:self.formatData];
self.formatOra = [NSDateFormatter dateFormatFromTemplate:#"j:mm" options:0 locale:[NSLocale currentLocale]];
[self.formatterOra setDateFormat:self.formatOra];
self.dal = NSLocalizedString(#"from", nil);
self.ore = NSLocalizedString(#"at", nil);
CLLocation *vLoc = [[CLLocation alloc] initWithLatitude:self.geo.latitude longitude:self.geo.longitude];
CLLocation *user = [[CLLocation alloc] initWithLatitude:self.userGeo.latitude longitude:self.userGeo.longitude];
CLLocationDistance distance = [user distanceFromLocation:venueLoc];
if ([[prefs objectForKey:#"unit"] isEqualToString:#"km"]) {
cell.lblDist.text = [NSString stringWithFormat:#"%.1f Km", distance /1000];
} else {
cell.lblDist.text = [NSString stringWithFormat:#"%.1f Miles", distance /1609];
}
// compare the object's starting date with the current date to set some images in the cell
NSComparisonResult startCompare = [[self.hH[indexPath.row] objectForKey:#"startDate"] compare: [NSDate date]];
if (startCompare == NSOrderedDescending) {
cell.quad.image = [UIImage imageNamed:#"no_HT"];
cell.lblStartTime.textColor = [UIColor redColor];
} else {
cell.quad.image = [UIImage imageNamed:#"yes_HT"];
cell.lblStartTime.textColor = [UIColor colorWithRed:104.0/255.0 green:166.0/255.0 blue:66.0/255.0 alpha:1.0];
}
NSString *dataInizio = [NSString stringWithFormat:#"%# %# %# %#", self.dal, [self.formatterData stringFromDate:[self.hH[indexPath.row] objectForKey:#"startDate"]], self.ore, [self.formatterOra stringFromDate:[self.hH[indexPath.row] objectForKey:#"endDate"]]];
cell.lblStartTime.text = dataInizio;
PFObject *cat = [self.hH[indexPath.row] objectForKey:#"catParent"];
NSString *languageCode = [[NSLocale preferredLanguages] objectAtIndex:0];
if ([languageCode isEqualToString:#"it"]) {
cell.lblCategory.text = [cat objectForKey:#"nome_it"];
} else if ([languageCode isEqualToString:#"es"]) {
cell.lblCategory.text = [cat objectForKey:#"nome_es"];
} else {
cell.lblCategory.text = [cat objectForKey:#"nome_en"];
}
//getting the image data from the Parse PFFile
PFFile *theImage = [self.hH[indexPath.row] objectForKey:#"photo"];
[theImage getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
cell.cellImageView.image = [UIImage imageWithData:data];
}
}];
//getting the cell object's owner and his profile
PFUser *usr = [self.hH[indexPath.row] objectForKey:#"parent"];
PFQuery *prof = [PFQuery queryWithClassName:#"Profile"];
prof.cachePolicy = kPFCachePolicyCacheThenNetwork;
[prof whereKey:#"parent" equalTo:usr];
[prof getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
//getting the object's rating and the number of votes
PFQuery *rateQuery = [PFQuery queryWithClassName:#"Rating"];
[rateQuery whereKey:#"parent" equalTo:object];
[rateQuery getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
float vote = [[object objectForKey:#"rate"] floatValue];
float temp = ((vote * 2) + 0.5);
int tempvote = (int)temp;
float roundedVote = (float)tempvote / 2;
// drawing the stars number, depending on the rating obtained
UIImage *starsImage = [UIImage imageNamed:#"stars"];
UIGraphicsBeginImageContextWithOptions(cell.imgVoto.frame.size, NO, 0);
CGPoint starPoint = (CGPoint) {
.y = (cell.imgVoto.frame.size.height * (2 * roundedVote + 1)) - (starsImage.size.height)
};
[starsImage drawAtPoint:starPoint];
cell.imgVoto.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
cell.lblVoto.text = [NSString stringWithFormat:#"(%d)", [[object objectForKey:#"voters"] intValue]];
}
}];
}
}];
return cell;
}
EDIT: this is the cell code:
+ (void)initialize {
if (self != [HH class]) {
return;
}
}
-(id)initWithCoder:(NSCoder *)aDecoder {
if ( !(self = [super initWithCoder:aDecoder]) ) return nil;
self.cellImageView.image = [UIImage imageNamed:#"icona_foto"];
self.cellImageView.contentMode = UIViewContentModeScaleToFill;
self.formatterData = [[NSDateFormatter alloc] init];
self.formatData = [[NSString alloc] init];
self.formatterOra = [[NSDateFormatter alloc] init];
self.formatOra = [[NSString alloc] init];
self.formatData = [NSDateFormatter dateFormatFromTemplate:#"dd/MM" options:0 locale:[NSLocale currentLocale]];
[self.formatterData setDateFormat:self.formatData];
self.formatOra = [NSDateFormatter dateFormatFromTemplate:#"j:mm" options:0 locale:[NSLocale currentLocale]];
[self.formatterOra setDateFormat:self.formatOra];
self.lblVoto.text = #"(0)";
return self;
}
SECOND EDIT: this is the code in the viewDidLoad method:
PFQuery *hours = [PFQuery queryWithClassName:#"HH"];
hours.cachePolicy = kPFCachePolicyCacheThenNetwork;
// here I'm making lots of query constraints that I'll not include
[hours findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.objectsNumber = objects.count;
self.hH = [[NSArray alloc] initWithArray:objects];
}
}];
[self.tableView reloadData];
}
I would move as much of the logic out of cellForRowAtIndexPath: as you can, it needs to be very light-weight to get good scrolling performance. You're doing a lot of work on the main thread, and I would do a lot more of this work when you get your model objects back from Parse (if you could post viewDidLoad I can give you more specific help) and update the table view when these calls are done:
[UIImage imageWithData:data]
anything to do with NSDateFormatter
CLLocation's initWithLatitude:longitude:
creating the rating stars image
None of these depend on the state of the table view, so they can be effectively precomputed and cached in a model object. If you simply scroll up and down the table, you're doing allo f the same work over and over, killing your performance.
Updated for the questioner's newest code:
I won't include all of your functionality here but this should give you an idea:
// create a single shared formatter instead of one per object
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatFromTemplate:#"dd/MM" options:0 locale:[NSLocale currentLocale]];
NSDateFormatter *timeFormatter = [NSDateFormatter dateFormatFromTemplate:#"j:mm" options:0 locale:[NSLocale currentLocale]];
[hours findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.objectsNumber = objects.count;
for (SomeObject *modelObj in objects) {
// if you can add properties to your model object directly, do that
// otherwise write a category on the Parse object to add the ones you need
modelObj.dateString = [NSString stringWithFormat:#"%# %# %# %#", modelObj.dal, [self.dateFormatter stringFromDate:[modelObj objectForKey:#"startDate"]], modelObj.ore, [self.timeFormatter stringFromDate:[modelObj objectForKey:#"endDate"]]];
// create your locations, images, etc in here too
}
self.hH = [[NSArray alloc] initWithArray:objects];
}
}];]
Then in cellForRowAtIndexPath:, take the precomputed properties and simply assign them to the appropriate labels, image views, etc.
It would be even better to do most of this processing off the main thread via GCD, but that is most likely out of scope for this question. See Using GCD and Blocks Effectively for more information. Just remember do only interact with UIKit from the main thread!
have a try by removing
CLLocation *vLoc = [[CLLocation alloc] initWithLatitude:self.geo.latitude longitude:self.geo.longitude];
CLLocation *user = [[CLLocation alloc] initWithLatitude:self.userGeo.latitude long itude:self.userGeo.longitude];
CLLocationDistance distance = [user distanceFromLocation:venueLoc];
This was at first sight , then I see your all your code and I realize a lot of image are used
Because UITableView takes some time to layout cells.
Solution:
step1. Set section number and row number to 0.
step2. Reload tableView in viewDidAppear.
Then your view controller cloud response quickly and then show cells.

How to publish Facebook actions that include maps using iOS SDK?

I want to publish an Open Graph fitness:runs action on Facebook and I want it to render with a map of my path. The path is defined by the path coordinates below. How do I do this? The method below publishes the action and I can see the text for the action in my Activity Log on Facebook and in my timeline. But I do not see a map when I hoover over any element of the posted action. What am I doing wrong?
- (void) fbPost:(NSString *)txt toList:(NSString *)listId { // post
[FBSession setActiveSession:[FacebookManager instance].facebook.session];
NSMutableDictionary<FBGraphObject> *action = [FBGraphObject graphObject];
action[#"course"] = #"http://samples.ogp.me/48586838281818";
action[#"privacy"] = privacyStr;
NSMutableArray *coords = [NSMutableArray arrayWithCapacity:59];
for (int i = 0; i < 59; i++)
{
NSMutableDictionary *coord = [[NSMutableDictionary alloc] initWithCapacity:3];
#define TIMESTAMP #"fitness:metrics:timestamp"
#define LATITUDE #"fitness:metrics:location:latitude"
#define LONGITUDE #"fitness:metrics:location:longitude"
[coord setValue:[NSString stringWithFormat:#"2013-04-01T12:%2d:00+0000", i] forKey:TIMESTAMP];
[coord setValue:[NSString stringWithFormat:#"%f", 37.442564 + i * 0.00001] forKey:LATITUDE];
[coord setValue:[NSString stringWithFormat:#"%f", -122.164879 + i * 0.000001] forKey:LONGITUDE];
[coords addObject:coord];
NSLog(#"coord=%# i=%d", coord, i);
}
action[#"path"] = [coords JSONString];
action[#"message"] = txt;
[FBRequestConnection startForPostWithGraphPath:#"me/fitness.runs"
graphObject:action
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (!error) // it's a post, save id
{
}
else
{
}
}];
}
NSMutableDictionary<FBGraphObject> *action = [FBGraphObject graphObject];
NSMutableDictionary<FBGraphObject> *course = [FBGraphObject openGraphObjectForPost];
course[#"og:title"] = #"My Workout";
course[#"og:type"] = #"fitness.course"; //very important
course[#"og:url"] = #"www.fitness.com"; // give a meaningful url here
course[#"fitness:duration:value"] = #"3000";
course[#"fitness:duration:units"] = #"s";
course[#"fitness:calories"] = #"100";
course[#"fitness:distance:value"] = 1.7;
course[#"fitness:distance:units"] = #"mi";
course[#"fitness:speed:value"] = #"2";
course[#"fitness:speed:units"] = #"m/s";
course[#"fitness:pace:value"] = #"0.5";
course[#"fitness:pace:units"] = #"s/m";
course[#"og:description"] = #"course_description";
NSMutableArray *locationDataPointsArray = [[NSMutableArray alloc] init];
locationDataPointsArray[0] = #{#"location:latitude": 12.91277, #"location:longitude": 77.56671};
locationDataPointsArray[1] = #{#"location:latitude": 12.91284, #"location:longitude": 77.56681};
locationDataPointsArray[2] = #{#"location:latitude": 12.91297, #"location:longitude": 77.56691};
course[#"fitness:metrics"] = locationDataPointsArray;
action[#"fb:explicitly_shared"] = #"true";
action[#"course"] = course;
NSString *path = #”me/fitness.runs”;
//for custom story: NSString *path = #”me/urNamespace:name of ur action”;
[FBRequestConnection startForPostWithGraphPath:path graphObject:action completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSLog(#"Posted fitness action, id: %#", [result objectForKey:#"id"]);
NSString *alertText = #"Workout successfully posted to Facebook :)";
NSString *alertTitle = #"Success";
[[[UIAlertView alloc] initWithTitle:alertTitle message:alertText delegate:nil cancelButtonTitle:#"OK!" otherButtonTitles:nil] show];
}
else {
NSLog(#"error in posting action %#", error.description);
}
}];
I don't really know how to answer you question however I read some documents the other day and they may be useful to you...
I would Recommend
That you take a read of this document and hopefully you will be able to understand how to integrate this in your app.
You may also want to take a read of this
& this
Happy coding :)

Resources