I have the following function that I believe is being run in the main thread (it is the event assigned to a button click)
-(void)startTracking:(CLLocation*) targetLocation
{
NSLog(#"Target location: %#", targetLocation);
self.locationManager = [[CLLocationManager alloc]init];
[self.locationManager setDelegate:self];
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.targetRegion = [[CLRegion alloc] initCircularRegionWithCenter:targetLocation.coordinate radius:10 identifier:#"Destination Region"];
[self.locationManager startMonitoringForRegion:self.targetRegion];
//[self.locationManager startUpdatingLocation];
NSLog(#"Target region: %#", self.targetRegion);
}
The only reason I say "i think", is that before this can be run, I get the targetRegion details in a block run on another thread.
[geocoder geocodeAddressString:self.address completionHandler:^(NSArray* placemarks, NSError* error){
for (CLPlacemark* aPlacemark in placemarks)
{ // Process the placemark.
NSLog(#"Got Placemark : %#", aPlacemark);
//newDestination.destination = aPlacemark.location;
}
//self.Destination.destination = [[placemarks objectAtIndex:0] location];
self.targetLocation = [[placemarks objectAtIndex:0] location];
self.startTrackingButton.enabled = true;
self.stopTrackingButton.enabled = true;
}];
Is this the reason why the delegate is not being called...?
Related
I have view controller that prompts the user to enter in some location information, then click submit. When that happens, the data is thrown into a place dictionary and then geocoded through the methods updatePlaceDictionary and geocode. [userListing saveInBackground] then sends the object to an online database. Here is the submit method, which is called when the user fills in the information and clicks submit, along with the updatePlaceDictionary and geocode methods:
- (void)submit{
PFObject* userListing = [PFObject objectWithClassName:#"userListing"];
[self updatePlaceDictionary];
[self geocode];
[userListing setObject:listingLocation forKey:#"location"];
[userListing saveInBackground];
[listings addObject:userListing];
[self.navigationController popViewControllerAnimated:YES];
}
- (void)updatePlaceDictionary {
[self.placeDictionary setValue:self.streetField.text forKey:#"Street"];
[self.placeDictionary setValue:self.cityField.text forKey:#"City"];
[self.placeDictionary setValue:self.stateField.text forKey:#"State"];
[self.placeDictionary setValue:self.zipField.text forKey:#"ZIP"];
}
- (void)geocode{
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressDictionary:self.placeDictionary completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
listingLocation = [PFGeoPoint geoPointWithLatitude:coordinate.latitude longitude:coordinate.longitude];
} else {
NSLog(#"error");
}
}];
}
All three methods work perfectly fine. The problem is, in the submit method, the line:
[userListing setObject:listingLocation forKey#"location"];
just ends up giving the key "location" a value of (0,0). This is occurring because geocode runs asynchronously, and does not finish by the time the above line is reached. How can I have this value set AFTER geocode is finished running?
You entire code here is going to have to be a little asynchronous. Your geocode method can have a block callback passed in, and call it when you are done with the geocode.
- (void)submit{
PFObject* userListing = [PFObject objectWithClassName:#"userListing"];
[self updatePlaceDictionary];
[self geocode:^{
[userListing setObject:listingLocation forKey:#"location"];
[userListing saveInBackground];
[listings addObject:userListing];
[self.navigationController popViewControllerAnimated:YES];
}];
}
- (void)updatePlaceDictionary {
[self.placeDictionary setValue:self.streetField.text forKey:#"Street"];
[self.placeDictionary setValue:self.cityField.text forKey:#"City"];
[self.placeDictionary setValue:self.stateField.text forKey:#"State"];
[self.placeDictionary setValue:self.zipField.text forKey:#"ZIP"];
}
- (void)geocode:(void (^)(void))callback {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressDictionary:self.placeDictionary completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
listingLocation = [PFGeoPoint geoPointWithLatitude:coordinate.latitude longitude:coordinate.longitude];
if (callback) {
callback();
}
} else {
NSLog(#"error");
}
}];
}
I am building a rails-backed ios app that uses AFNetworking to POST content to a server. A user can upload a photo with a comment - and this works. I also want to have the option to let a user upload just text- this is where I am having trouble. I have one method for saving a photo and text, and another method for saving just text. The save photo method works, but the save text method creates a post but the text is null.
The save photo implementation is like this:
- (void)savePhotoAtLocation:(CLLocation *)location
withBlock:(void (^)(CGFloat))progressBlock completion:(void (^)(BOOL, NSError *))completionBlock {
if (!self.content) self.content = #"";
NSDictionary *params = #{
#"post[content]" : self.content,
#"post[lat]": #(location.coordinate.latitude),
#"post[lng]": #(location.coordinate.longitude)
};
NSURLRequest *postRequest = [[APIClient sharedClient] multipartFormRequestWithMethod:#"POST" path:#"/posts" parameters:params
constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
{
[formData appendPartWithFileData:self.photoData
name:#"post[photo]"
fileName:#""
mimeType:#"image/png"];
}];
AFHTTPRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:postRequest];
This method only works when there is photoData- if you don't have photoData, the app crashes.
So I am wondering what is the equivalent to a multipartFormRequest- that lets you only include a string?
This is what I have right now- which creates a post- but returns content: as well as the lat/lng params which should be returned with the current location.
This is defined in the post model
- (void)savePostAtLocation:(CLLocation *)location
withBlock:(void (^)(CGFloat progress))progressBlock completion:(void (^)(BOOL success, NSError *error))completionBlock {
if (!self.content) self.content = #"";
NSDictionary *params = #{
#"post[content]" : self.content,
#"post[lat]" : #(location.coordinate.latitude),
#"post[lng]" : #(location.coordinate.longitude)
};
NSURLRequest *postRequest = [[APIClient sharedClient]requestWithMethod:#"POST" path:#"/posts" parameters:params];
AFHTTPRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:postRequest];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (operation.response.statusCode == 200 || operation.response.statusCode == 201) {
NSLog(#"Created, %#", responseObject);
NSDictionary *updatedPost = [responseObject objectForKey:#"post"];
[self updateFromJSON:updatedPost];
[self notifyCreated];
completionBlock(YES, nil);
} else {
completionBlock(NO, nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionBlock(NO, error);
}];
[[APIClient sharedClient] enqueueHTTPRequestOperation:operation];
}
And in the AddPostViewController save calls this:
- (void)save:(id)sender
{
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 80.0f;
[locationManager startUpdatingLocation];
[self getLocation];
CLLocation * location = [locationManager location];
Post *post = [[Post alloc] init];
post.content = self.contentTextField.text;
[self.view endEditing:YES];
ProgressView *progressView = [ProgressView presentInWindow:self.view.window];
if (location) {
[post savePostAtLocation:self.locationManager.location withBlock:^(CGFloat progress) {
[progressView setProgress:progress];
} completion:^(BOOL success, NSError *error) {
[progressView dismiss];
if (success) {
[self.navigationController popViewControllerAnimated:YES];
} else {
NSLog(#"ERROR: %#", error);
}
}];
} else {
NSLog(#"No Location");
}
}
Here is the log after a post is created. As you can see the attributes are null- and shouldn't be.
Created, {
post = {
content = "<null>";
"created_at" = "2013-07-21T18:45:12Z";
id = 13;
lat = "<null>";
lng = "<null>";
success = 1;
}
So the fact that a post is created but the attributes are null makes me think that the problem is simply in the NSURLRequest- and that I am not fully implementing the AFNetworking protocol but I haven't been able to find a way to implement a post request that doesn't entail fileData. How do I make a post request that doesn't append fileData?
Any help would be greatly appreciated.
Thanks!
You can copy your existing method but instead of using appendPartWithFileData:name:fileName:mimeType: to set file data you can convert your parameters to data and add them with appendPartWithFormData:name:.
This is how I got it to work:
post.h
+ (void)createNoteAtLocation:(CLLocation *)location
withContent:(NSString *)content
block:(void (^)(Post *post))block;
post.m
+ (void)createNoteAtLocation:(CLLocation *)location
withContent:(NSString *)content
block:(void (^)(Post *post))block
{
NSDictionary *parameters = #{ #"post": #{
#"lat": #(location.coordinate.latitude),
#"lng": #(location.coordinate.longitude),
#"content": content
}
};
[[APIClient sharedClient] postPath:#"/posts" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
Post *post = [[Post alloc] initWithDictionary:responseObject];
if (block) {
block(post);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (block) {
block(nil);
}
}];
}
And finally in the createPostViewController:
- (void)save:(id)sender
{
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 80.0f;
[locationManager startUpdatingLocation];
[self getLocation];
CLLocation * location = [locationManager location];
Post *post = [[Post alloc] init];
post.content = self.contentTextField.text;
[self.view endEditing:YES];
if (location) {
[Post createNoteAtLocation:location withContent:self.contentTextField.text block:^(Post *post) {
NSLog(#"Block: %#", post);
[self.navigationController popViewControllerAnimated:YES];
}];
}
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I've got myself some of a newbie problem.
I got this method to determine the zip code where the iPhone is located, based on GPS coordinates. Reverse Geocoding. My method works, I know this, since it has no problem writing out the correct zip code to a label.
But I need this zip code to be stored in a string that I can use inside a method I use to compose a SMS.
Anyone can help me with that?
Tell me if an source code is necessary! (Just not currently sitting on my work comp)
Clearly i've been misunderstood, should have posted som code.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
// Reverse Geocoding
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
**postalCode** = [NSString stringWithFormat:#"%#",
placemark.postalCode];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
}
Here i try to save the zip code inside the NSString named postalCode (highlighted with "**")
I try to load it again in sms composer
-(void)displaySMSComposerSheet
{
CLLocation *currentLocation;
// Reverse Geocoding
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
postalCode = [NSString stringWithFormat:#"%#",
placemark.postalCode];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
picker.recipients = [NSArray arrayWithObjects:#"1220", nil];
picker.body = [NSString stringWithFormat:#"Dog %#", (placemark.)postalCode];
picker.messageComposeDelegate = self;
[self presentModalViewController:picker animated:YES];
}
only prints out in the SMS window:
Dog (null)
And i'm sure i have the coordinates, they get printed out in the output.
Hope this helps to understand the question better
#import <CoreLocation/CoreLocation.h>
#interface SomeController : UIViewController <CLLocationManagerDelegate>
#property (strong,nonatomic) CLLocationManager *locationManager;
#end
#implementation SomeController
-(void) trackUpdates
{
self.locationManager = [CLLocationManager new];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
self.locationManager.distanceFilter = 10.0f;
if ([CLLocationManager locationServicesEnabled]){
[self.locationManager startUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLGeocoder* gcrev = [[CLGeocoder alloc] init];
[gcrev reverseGeocodeLocation:[locations lastObject]
completionHandler:^(NSArray *placemarks, NSError *error)
{
CLPlacemark* revMark = [placemarks objectAtIndex:0];
NSString *zip = [revMark.addressDictionary objectForKey:#"ZIP"];
NSLog(#"%#",zip);
// ... do something with the zip, store in an ivar, call a method, etc.
}];
}
-(void)viewDidLoad {
[super viewDidLoad];
[self trackUpdates];
}
#end
I have problem with the localization API in Core Location Services. I get the promt that request permission to the location services. If I click Allow and goes to Settings I can see that my app don't have permission.
This is my code in my GeoUtility class:
CLGeocoder *reverseGeocoder = [[CLGeocoder alloc] init];
CLLocationManager *lm = [[CLLocationManager alloc] init];
[lm setPurpose:#"Need to verify your region"];
[lm startUpdatingLocation];
It's trigged by a viewController in the viewDidAppear
I also have added location-services under Required Devices Capabilites in my plist file.
Add CoreLocation.framework and MapKit.framework
And
in .h
#import <MapKit/MapKit.h>
CLLocationManager *locationManager;
CLGeocoder *geocoder;
in view did load
- (void)viewDidLoad
{
locationManager = [[CLLocationManager alloc] init];
geocoder = [[CLGeocoder alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
then
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
LongitudeLbl.text = [NSString stringWithFormat:#"%.8f",currentLocation.coordinate.longitude];
LatitudeLbl.text = [NSString stringWithFormat:#"%.8f",currentLocation.coordinate.latitude];
}
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
NSString *addresstemp2 = [[NSString alloc] init];
NSString *subThoroughfare2 = [NSString stringWithFormat:#"%#",placemark.subThoroughfare];
NSString *thoroughfare2 = [NSString stringWithFormat:#"%#",placemark.thoroughfare];
NSString *postalCode2 = [NSString stringWithFormat:#"%#",placemark.postalCode];
NSString *locality2 = [NSString stringWithFormat:#"%#",placemark.locality];
NSString *administrativeArea2 = [NSString stringWithFormat:#"%#",placemark.administrativeArea];
NSString *country2 = [NSString stringWithFormat:#"%#",placemark.country];
if (![subThoroughfare2 isEqualToString:#"(null)"]) {
addresstemp2 = [NSString stringWithFormat:#"%#",subThoroughfare2];
}
if (![thoroughfare2 isEqualToString:#"(null)"]) {
addresstemp2 = [NSString stringWithFormat:#"%# %# \n",addresstemp2,thoroughfare2];
}
if (![postalCode2 isEqualToString:#"(null)"]) {
addresstemp2 = [NSString stringWithFormat:#"%# %#",addresstemp2,postalCode2];
}
if (![locality2 isEqualToString:#"(null)"]) {
addresstemp2 = [NSString stringWithFormat:#"%# %# \n",addresstemp2,locality2];
}
if (![administrativeArea2 isEqualToString:#"(null)"]) {
addresstemp2 = [NSString stringWithFormat:#"%# %# \n",addresstemp2,administrativeArea2];
}
if (![country2 isEqualToString:#"(null)"]) {
addresstemp2 = [NSString stringWithFormat:#"%# %#",addresstemp2,country2];
}
AddressLbl.text = [[NSString alloc] initWithString:addresstemp2];
[AddressLbl sizeToFit];
[locationManager stopUpdatingLocation];
} else {
}
} ];
}
And you also change setting in your Simulator GO TO THE setting and choose Location Service change it to ON. see down is your application name if it is off then change to ON
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
[window addViewForTouchPriority:viewController.view];
if(self.locationManager==nil){
locationManager=[[CLLocationManager alloc] init];
locationManager.delegate=self;
locationManager.purpose = #"We will try to tell you where you are if you get lost";
locationManager.desiredAccuracy=kCLLocationAccuracyBest;
locationManager.distanceFilter=500;
self.locationManager=locationManager;
}
geoCoder = [[CLGeocoder alloc] init];
if([CLLocationManager locationServicesEnabled]){
[self.locationManager startUpdatingLocation];
}
return YES;
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
lati = [[NSString alloc] initWithFormat:#"%+.6f", newLocation.coordinate.latitude];
NSLog(#"address:%#",lati);
longi = [[NSString alloc] initWithFormat:#"%+.6f", newLocation.coordinate.longitude];
NSLog(#"address:%#",longi);
CLLocationCoordinate2D coord;
coord.latitude = [lati doubleValue];
coord.longitude = [longi doubleValue];
[geoCoder reverseGeocodeLocation: newLocation completionHandler: ^(NSArray *placemarks, NSError *error)
{
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
address = [[NSString alloc]initWithString:locatedAt];
NSLog(#"address:%#",address);
}];
}
I am using above code to get address by giving latitude and longitude, but control is not entering in to geocoder method, it skips it. Can anybody help me in it.
Thanks in advance.
It doesn't matter, control does not enter in the method, but it works, note the output it will work.
that is normal, because the code inside the reverseGeocodeLocation is execute inside a block.
The execution of the code inside a block occurs in another thread, so is not execute in the main thread, that's why the control don't enter inside the geocoder method.