Cannot AddObject to NSMutableArray from Block - ios

I have a feeling that my problem here is really with blocking, but maybe it's something else too. I am trying to forward geocode an address and place the coordinates into an array to use later.
An exception is raised down at the bottom when I try to call on one of the objects I tried added to the array in the block. The exception also gets raised before any of the NSLogs ever print out within the block text.
What's the proper way to handle this? Thanks.
- (NSMutableArray *)convertAddressToGeocode:(NSString *)addressString
{
//return array with lat/lng
__block NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:0];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:addressString
completionHandler:^ (NSArray* placemarks, NSError* error) {
for (CLPlacemark* aPlacemark in placemarks)
{
// Process the placemark.
if (error){
NSLog(#"Geocode failed with error: %#", error);
[self displayError:error];
return;
}
else {
NSArray const *keys = #[#"coordinate.latitude",
#"coordinate.longitude",
#"altitude",
#"horizontalAccuracy",
#"verticalAccuracy",
#"course",
#"speed",
#"timestamp"];
NSString *keylat = keys[0];
NSString *keylng = keys[1];
if (aPlacemark.location == nil)
{
NSLog(#"location is nil.");
}
else if ([keylat isEqualToString:#"coordinate.latitude"] && [keylng isEqualToString:#"coordinate.longitude"])
{
NSString *lat = #"";
NSString *lng = #"";
lat = [self displayStringForDouble: [aPlacemark.location coordinate].latitude];
lng = [self displayStringForDouble: [aPlacemark.location coordinate].longitude];
NSLog(#"This never gets executed"): //THIS NEVER GETS EXECUTED
[coordinates addObject:[NSString stringWithFormat:#"%#",lat]];
[coordinates addObject:[NSString stringWithFormat:#"%#",lng]];
}}}}];
NSLog(#"Array: %#", coordinates[0]); //EXCEPTION RAISED HERE, Nothing ever gets added
return coordinates;
}
Here is the code this method is supposed to be plugged into, but I'm not getting the coordinates out of convertAddresstoGeocode to pass to convertCoordinatestoRepModel:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
NSString *addressToSearch = self.addressSearchField.text;
NSMutableArray *coordinateArray = [self convertAddressToGeocode:addressToSearch];
NSMutableArray *repModelArray = [self convertCoordinatesToRepModel:coordinateArray];
...
}

if geocodeAddressString is async operation than your block will be performed after
NSLog(#"Array: %#", coordinates[0]);
also, after call of your method ends (when event already handled) the coordinates array
released (it is because of __block modifier - blocks do not retain objects with __block modifier), and in your block you try to use dealloced coordinates array.
Once again:
Your block will be called after NSLog(#"Array: %#", coordinates[0]);
f.e.:
Remove NSLog(#"Array: %#", coordinates[0]); - it is normal that in that moment array is empty.
Store your coordinates array in some #property , you can release it after using in block
UPDATE:
in .h file
typedef void (^ConverteArrayCallback)(NSArray *coordinates);
under #intrerface
- (void)convertAddressToGeocode:(NSString *)addressString callback:(ConverteArrayCallback) callback;
in .m file
- (void)convertAddressToGeocode:(NSString *)addressString callback:(ConverteArrayCallback) callback {
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:0];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:addressString
completionHandler:^ (NSArray* placemarks, NSError* error) {
for (CLPlacemark* aPlacemark in placemarks)
{
// Process the placemark.
if (error){
NSLog(#"Geocode failed with error: %#", error);
[self displayError:error];
return;
}
else {
NSArray const *keys = #[#"coordinate.latitude",
#"coordinate.longitude",
#"altitude",
#"horizontalAccuracy",
#"verticalAccuracy",
#"course",
#"speed",
#"timestamp"];
NSString *keylat = keys[0];
NSString *keylng = keys[1];
if (aPlacemark.location == nil)
{
NSLog(#"location is nil.");
}
else if ([keylat isEqualToString:#"coordinate.latitude"] && [keylng isEqualToString:#"coordinate.longitude"])
{
NSString *lat = #"";
NSString *lng = #"";
lat = [self displayStringForDouble: [aPlacemark.location coordinate].latitude];
lng = [self displayStringForDouble: [aPlacemark.location coordinate].longitude];
NSLog(#"This never gets executed"): //THIS NEVER GETS EXECUTED
[coordinates addObject:[NSString stringWithFormat:#"%#",lat]];
[coordinates addObject:[NSString s
tringWithFormat:#"%#",lng]];
}}}
if (callback != NULL) {
callback(coordinates);
}
}];
}
That should works!
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
NSString *addressToSearch = self.addressSearchField.text;
[self convertAddressToGeocode:addressToSearch callback:^(NSArray *coordinates)
{
self.textView.text = [coordinates objectAtIndex:0];
}];
}

__block NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:0];
The problem is here; just replace the above code with:
NSMutableArray *coordinates = [[NSMutableArray alloc] init];

Related

Sort UITableView by distance

I am trying to sort my tableview in ascending order by distance that I calculate from coordinates. Everything works like a charm except I can't get it in ascending order, I have been mucking around with NSSortDescriptor etc., but getting unlucky, any help would be appreciated, here is my code:
- (void) retrieveData
{
NSURL *url = [NSURL URLWithString:jsonFile];
NSData *data = [NSData dataWithContentsOfURL:url];
_jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
_salesArray = [[NSMutableArray alloc]init];
for (int i = 0; i < _jsonArray.count; i++) {
NSString *sID = [[_jsonArray objectAtIndex:i] objectForKey:#"id"];
NSString *sName = [[_jsonArray objectAtIndex:i] objectForKey:#"name"];
NSString *sAddress = [[_jsonArray objectAtIndex:i] objectForKey:#"address"];
NSString *sPostcode = [[_jsonArray objectAtIndex:i] objectForKey:#"postcode"];
__block NSString *distance;
CLGeocoder *geocoder = [[CLGeocoder alloc]init];
[geocoder geocodeAddressString:sPostcode completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && placemarks.count > 0) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocation *myLocation = self.manager.location;
CLLocationDistance miles = [location distanceFromLocation:myLocation];
//this is the variable i want in my convenience init.
distance = [NSString stringWithFormat:#"%.1f m", (miles/1609.344)];
}
}];
[_salesArray addObject:[[sales alloc] initWithSales:sID andName:sName andAddress:sAddress andPostcode:distance]];
}
[_salesArray sortUsingComparator:
^NSComparisonResult(id obj1, id obj2){
sales *p1 = (sales *)obj1;
sales *p2 = (sales *)obj2;
if (p1.postcode > p2.postcode) {
return (NSComparisonResult)NSOrderedDescending;
}
if (p1.postcode < p2.postcode) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}
];
[self.tableView reloadData];
}
There are a few of issues here:
The geocodeAddressString imposes a few limitations, as outlined in the documentation:
This method submits the specified location data to the geocoding server asynchronously and returns. Your completion handler block will be executed on the main thread. After initiating a forward-geocoding request, do not attempt to initiate another forward- or reverse-geocoding request.
Geocoding requests are rate-limited for each app, so making too many requests in a short period of time may cause some of the requests to fail. When the maximum rate is exceeded, the geocoder passes an error object with the value kCLErrorNetwork to your completion handler.
Several key observations here:
This runs asynchronously (so you cannot call geocodeAddressString and use its results immediately afterwards). You have do invoke the work contingent on the geocoding inside the completion block.
You should not be starting the next geocode request until the prior one completes.
This means that you have to geocode the first postal code, let it complete asynchronously (i.e. later), geocode the next one, let it complete, etc., and only then do your sort and reload the table. A simple for loop is not an appropriate way to do this. You can either write a method that does a single geocode and invokes the next geocode in the completion block, or you can use NSOperation subclass as I have below.
I would advise storing the distance as a NSNumber. In MVC, the one decimal place string representation is a "view" behavior, and should probably not be part of the "model".
The advantage of this is that when you want to sort the objects, you can simply invoke the compare method for the NSNumber. For example, if salesPersonnel was a NSMutableArray of objects which each SalesPerson object has the NSNumber property called distance, you could then do:
[self.salesPersonnel sortUsingComparator:^NSComparisonResult(SalesPerson *obj1, SalesPerson *obj2) {
return [obj1.distance compare:obj2.distance];
}];
I wasn't sure if your sales entries per actual sales transactions or sales personnel, so I apologize if I misinterpreted the object types, but hopefully this illustrates the idea.
You can do this any way you want, but for me, when I want to run a number of asynchronous tasks, but do so sequentially, I gravitate to concurrent NSOperation subclass which I'll add to a serial NSOperationQueue.
NSError *error;
NSArray *addressEntries = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSAssert(addressEntries, #"unable to parse: %#", error);
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
self.salesPersonnel = [NSMutableArray array];
// define sort operation that will be called when all of the geocode attempts are done
NSOperation *sortAndReloadTableOperation = [NSBlockOperation blockOperationWithBlock:^{
[self.salesPersonnel sortUsingComparator:^NSComparisonResult(SalesPerson *obj1, SalesPerson *obj2) {
return [obj1.distance compare:obj2.distance];
}];
[self.tableView reloadData];
}];
// create the geocode operations
for (NSDictionary *addressEntry in addressEntries) {
SalesPerson *salesPerson = [[SalesPerson alloc] initWithSalesId:addressEntry[#"id"]
name:addressEntry[#"name"]
address:addressEntry[#"address"]
postalCode:addressEntry[#"postcode"]];
[self.salesPersonnel addObject:salesPerson];
NSOperation *geocodeOperation = [[GeocodeOperation alloc] initWithPostalCode:salesPerson.postalCode completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks firstObject];
CLLocation *location = placemark.location;
CLLocationDistance meters = [location distanceFromLocation:self.currentLocation];
salesPerson.distance = #(meters / 1609.344);
}];
[sortAndReloadTableOperation addDependency:geocodeOperation]; // note, the final sort is dependent upon this finishing
[queue addOperation:geocodeOperation]; // go ahead and queue up the operation
}
// now we can queue the sort and reload operation, which won't start until the geocode operations are done
[[NSOperationQueue mainQueue] addOperation:sortAndReloadTableOperation];
And the GeocodeOperation is a basic concurrent NSOperation subclass:
// GeocodeOperation.h
#import <Foundation/Foundation.h>
typedef void(^GeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
#interface GeocodeOperation : NSOperation
#property (nonatomic, copy) GeocodeCompletionHandler geocodeCompletionHandler;
- (instancetype)initWithPostalCode:(NSString *)postalCode completionHandler:(GeocodeCompletionHandler)geocodeCompletionHandler;
#end
and the implementation (note, the main method is the only interesting bit here ... all the rest is routine concurrent NSOperation subclass code; personally, I move all of the concurrent NSOperation stuff into a base class, which cleans up this GeocodeOperation code, but I didn't want to confuse this further, so I've kept this simple):
// GeocodeOperation.m
#import "GeocodeOperation.h"
#import CoreLocation;
#interface GeocodeOperation ()
#property (nonatomic, readwrite, getter = isFinished) BOOL finished;
#property (nonatomic, readwrite, getter = isExecuting) BOOL executing;
#property (nonatomic, copy) NSString *postalCode;
#end
#implementation GeocodeOperation
#synthesize finished = _finished;
#synthesize executing = _executing;
- (CLGeocoder *)sharedGeocoder
{
static CLGeocoder *geocoder = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
geocoder = [[CLGeocoder alloc]init];
});
return geocoder;
}
- (instancetype)initWithPostalCode:(NSString *)postalCode completionHandler:(GeocodeCompletionHandler)geocodeCompletionHandler
{
self = [super init];
if (self) {
_postalCode = [postalCode copy];
_geocodeCompletionHandler = geocodeCompletionHandler;
}
return self;
}
- (void)main
{
[[self sharedGeocoder] geocodeAddressString:self.postalCode completionHandler:^(NSArray *placemarks, NSError *error) {
if (self.geocodeCompletionHandler) {
self.geocodeCompletionHandler(placemarks, error);
}
[self completeOperation];
}];
}
#pragma mark - NSOperation methods
- (void)start
{
if ([self isCancelled]) {
self.finished = YES;
return;
}
self.executing = YES;
[self main];
}
- (void)completeOperation
{
self.executing = NO;
self.finished = YES;
}
- (BOOL)isConcurrent
{
return YES;
}
- (void)setExecuting:(BOOL)executing
{
if (_executing != executing) {
[self willChangeValueForKey:#"isExecuting"];
_executing = executing;
[self didChangeValueForKey:#"isExecuting"];
}
}
- (void)setFinished:(BOOL)finished
{
if (_finished != finished) {
[self willChangeValueForKey:#"isFinished"];
_finished = finished;
[self didChangeValueForKey:#"isFinished"];
}
}
#end
I think the problem is postcode is an NSString. So in your block (p1.postcode > p2.postcode) is comparing the ADDRESS LOCATIONS, not the string values themselves.
You want to use the NSString function compare: instead of doing it yourself.
Try this:
[_salesArray sortUsingComparator:
^NSComparisonResult(id obj1, id obj2){
sales *p1 = (sales *)obj1;
sales *p2 = (sales *)obj2;
NSString *postcode1 = p1.postcode;
NSString *postcode2 = p2.postcode;
return [postcode1 compare:posecode2];
];

index 0 beyond bounds for empty array' libc++abi.dylib: terminate called throwing an exception

I am very new to xcode please guide me to correct the error, My code is,
//Set our mapView
[MapViewC setRegion:myRegion animated:NO];
CLLocation *someLocation=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
addressOutlet=[dictionary valueForKey:#"Street"];
City=[dictionary valueForKey:#"City"];
State=[dictionary valueForKey:#"State"];
if (addressOutlet!=NULL&&City!=NULL)
{
NSString *SubTitle=[NSString stringWithFormat:#"%#,%#,%#",addressOutlet,City,State];
cell.detailTextLabel.text=SubTitle;
}
else if (addressOutlet==NULL&&City!=NULL)
{
NSString *SubTitle=[NSString stringWithFormat:#"%#,%#,",City,State];
cell.detailTextLabel.text=SubTitle;
}
else if (addressOutlet!=NULL&&City==NULL)
{
NSString *SubTitle=[NSString stringWithFormat:#"%#,%#,",addressOutlet,State];
cell.detailTextLabel.text=SubTitle;
}
else if(addressOutlet==NULL&&City==NULL)
{
NSString *SubTitle=[NSString stringWithFormat:#"%#",State];
cell.detailTextLabel.text=SubTitle;
}
}];
Thanks in advance.
OK an array can be empty, in which case the following statement will cause an exception:
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
// ^
So guard against it, with something like:
if ([placemarks count] > 0) {
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
....
}
I haven't read the API docs for that completion handler, but you can probably test if error is non-nil and act accordingly (i.e. if error != nil respond to error, else process the placemarks array).

Adding mapview annotations within parse query returns null randomly

I am creating an iOS app using Parse database(asynchronously) to store information that will be used when populating a mapview. I have been trying to figure out what is wrong for a long time and have done plenty of research without any luck. I have, however, found the source of the issue.
In my code, I am querying the parse database in hopes of getting the information I want and then storing the information in a custom pointAnnotation class, which is of type MkPointAnnotation. Each item is stored in an array of pointAnnotations, and once all items in the database have been stored in the array, the annotations are added to MyMapView. --I have tried adding the annotations as they are created, which does not change anything.
The issue I have been having is that randomly, the query will iterate under the for(PFObject *vendor in Vendors) and reach an error, calling NSLog(#"%#", error.debugDescription); which shows (null) in the output log. The amount of objects that return null seems to change each time I run the application, and occasionally it will work as expected. After adding a do while(pointArray.count < query.countObjects), the function will iterate roughly 20-30 times and then will add the correct number of annotations, however, it is extremely inefficient.
Is this an inefficiency within Parse or is there a better way to achieve the expected results?
PFQuery *query = [PFQuery queryWithClassName:#"Vendors"];
[query orderByDescending:#"updatedAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *vendors, NSError *error){
NSMutableArray *pointArray = [[NSMutableArray alloc] init];
if (!error) {
// The find succeeded.
// Do something with the found objects
do {
pointArray = [[NSMutableArray alloc] init];
for (PFObject *vendor in vendors) {
NSDate *lastUpdated = vendor.updatedAt;
NSDate *today = [NSDate date];
NSDate *newDate = [lastUpdated dateByAddingTimeInterval:86400];
if (today <= newDate) {
PFGeoPoint *point = vendor[#"Location"];
NSString *vendor_ID = vendor[#"Vendor_ID"];
NSMutableArray *FruitList = vendor[#"Fruits"];
NSMutableArray *VeggieList = vendor[#"Veggies"];
NSMutableArray *addressArray = vendor[#"Address"];
NSString *startHr = vendor[#"Start_Time"];
NSString *endHr = vendor[#"End_Time"];
Boolean more = false;
NSString *moreString = vendor[#"And_More"];
if ([moreString isEqual: #"true"]) {
more = true;
}
CLLocationCoordinate2D location;
location.latitude = point.latitude;
location.longitude = point.longitude;
pointAnnotation *newAnnotation = [[pointAnnotation alloc] init];
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"language"] isEqual:#"ENGLISH"]){
FindCartsLabel.text = #"Find Carts within:";
MilesTextField.text = #"Show All";
milesArray=[[NSArray alloc]initWithObjects:#"Show All", #"1 Mile", #"5 Miles", #"10 Miles", #"20 Miles", nil];
AddressBar.placeholder = ENGLISH_Address;
newAnnotation.title = #"Good. To. Go. Vendor";
newAnnotation.fruits = FruitList;
newAnnotation.veggies = VeggieList;
}else if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"language"] isEqual:#"SPANISH"]){
FindCartsLabel.text = #"Encuentra Carros Dentro:";
newAnnotation.title = #"Good. To. Go. Vendedor";
AddressBar.placeholder = SPANISH_Address;
NSMutableArray *spanishFruitList = [[NSMutableArray alloc]init];
for (NSString *current in FruitList) {
MilesTextField.text = #"Mostrar Todo";
milesArray=[[NSArray alloc]initWithObjects:#"Mostrar Todo", #"1 Milla", #"5 Millas", #"10 Millas", #"20 Millas", nil];
if ([current isEqual:#"Apples"]) {
[spanishFruitList addObject:SPANISH_Apples];
}
if ([current isEqual:#"Bananas"]) {
[spanishFruitList addObject:SPANISH_Bananas];
}
if ([current isEqual:#"Citrus"]) {
[spanishFruitList addObject:SPANISH_Citrus];
}
if ([current isEqual:#"Mangos"]) {
[spanishFruitList addObject:SPANISH_Mangos];
}
if ([current isEqual:#"Strawberries"]) {
[spanishFruitList addObject:SPANISH_Strawberries];
}
if ([current isEqual:#"And More"]) {
[spanishFruitList addObject:SPANISH_More];
}
}
NSMutableArray *spanishVeggieList = [[NSMutableArray alloc]init];
for (NSString *current in VeggieList) {
if ([current isEqual:#"Avocados"]) {
[spanishVeggieList addObject:SPANISH_Avocados];
}
if ([current isEqual:#"Broccoli"]) {
[spanishVeggieList addObject:SPANISH_Broccoli];
}
if ([current isEqual:#"Carrots"]) {
[spanishVeggieList addObject:SPANISH_Carrots];
}
if ([current isEqual:#"Squash"]) {
[spanishVeggieList addObject:SPANISH_Squash];
}
if ([current isEqual:#"Onions"]) {
[spanishVeggieList addObject:SPANISH_Onions];
}
if ([current isEqual:#"Tomatoes"]) {
[spanishVeggieList addObject:SPANISH_Tomatoes];
}
if ([current isEqual:#"And More"]) {
[spanishVeggieList addObject:SPANISH_More];
}
}
newAnnotation.fruits = spanishFruitList;
newAnnotation.veggies = spanishVeggieList;
}
newAnnotation.coordinate = location;
newAnnotation.vendorID = vendor_ID;
newAnnotation.startHour = startHr;
newAnnotation.endHour = endHr;
newAnnotation.loc = point;
newAnnotation.isCustomAddress = false;
//newAnnotation.subtitle = address;
__block NSString *address = [NSString stringWithFormat:#"%# %#, %#, %#, %#",
addressArray[0], addressArray[1],
addressArray[2], addressArray[3],
addressArray[4]];
__block NSString *currAddress = [NSString stringWithFormat:#"%# %#\n"
"%#, %#, %#\n"
"%#\n",
addressArray[0], addressArray[1],
addressArray[2], addressArray[3],
addressArray[4], addressArray[5]];
newAnnotation.subtitle = address;
newAnnotation.addressFormatted = currAddress;
static NSString *identifier = #"MyLocation";
MKPinAnnotationView *currentView = [[MKPinAnnotationView alloc] initWithAnnotation:newAnnotation reuseIdentifier:identifier];
[pointArray addObject:currentView];
} else {
//[self viewDidLoad];
NSLog(#"%#", error.debugDescription);
}
//} ];
}
} while (pointArray.count < query.countObjects);
}
if (pointArray.count == query.countObjects) {
for (MKPinAnnotationView *currentPoint in pointArray) {
[self.MyMapView addAnnotation:currentPoint.annotation];
}
}
}];
Thanks in advance for the help. I do not really understand why this code would not complete after only one iteration.
The NSLog(#"%#", error.debugDescription); doesn't look like it's in the right place. It's in an else block that is associated with the if (today <= newDate) which is inside a block of code that is only executed if error is null which is why it says null in the log (when what it really means is "today > newDate"). – Anna

Getting the address based on latitude and longitude of multiple points

I'm trying to loop through an array of about 10 latitude and longitude values and get the address from them. I created a console application using Xcode and I'm able to loop the file and retrieve the locations, add them to an NSMutableArray and pass it to the below function. However the completion handler block never gets called. What could I be doing wrong? Let me know if you need to see any other code at this point. I'm just frustrated and confused and wonder what could it be.
void nextGeocodeRequest(int start, NSMutableArray * myLocations)
{
#autoreleasepool {
for (int i = start; i < 1; i++) {
[ myLocations objectAtIndex:i ];
double mylong = [[[myLocations objectAtIndex:i] valueForKey:#"Longitude"] doubleValue ];
double mylat = [[[myLocations objectAtIndex:i] valueForKey:#"Latitude"] doubleValue];
goal = [[CLLocation alloc] initWithLatitude: mylat longitude:mylong] ;
CLGeocoder * geocoder = [[CLGeocoder alloc]init];
[geocoder reverseGeocodeLocation:goal completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
NSLog(#"this is the state '%#'",placemark.locality);
/*
self.state = [[State alloc] init];
self.state.name = placemark.locality;
self.state.code = placemark.administrativeArea;
self.state.stateId = 1;
self.state.stations = 300;
[self.states addObject:self.state];
*/
//[self.tableView reloadData];
nextGeocodeRequest(i, myLocations);
} else {
NSLog(#"%#", error.debugDescription);
}
}];
} //ends the for
// return 0;
}
}
You need to run the current NSRunLoop at the end of your main function such that the geocoding connections will be processed. You then need to define how your app will terminate after all of the connections are processed.
[[NSRunLoop currentRunLoop] run];
(put this at the end of the auto release pool in your main function)
Currently your app does all of the inline processing, prepares a number of connections with nothing to process them and then simply exits.

Why mi property do not save the value when I use SudzC?

I am using SudzC to get webservices, that webservice give me data, I tried to save the data in a property, but when I use to fill a tableview the property don't have any data. I use the debugger to view the property.
This es my handler
- (void) ConsultarUnidadesOrganizacionalesPorEmpresaHandler: (id) value {
// Handle errors
if([value isKindOfClass:[NSError class]]) {
NSLog(#"%#", value);
return;
}
// Handle faults
if([value isKindOfClass:[SoapFault class]]) {
NSLog(#"%#", value);
return;
}
// Do something with the NSMutableArray* result
NSMutableArray *result = (NSMutableArray*)value;
NSMutableArray *unidadOrganizacional = [[NSMutableArray alloc] init];
self.myData = [NSMutableArray array];
for (int i = 0; i < [result count]; i++)
{
EWSUnidadNegocio *empresa = [[EWSUnidadNegocio alloc] init];
empresa = [result objectAtIndex:i];
[unidadOrganizacional addObject:[empresa Descripcion]];
}
self.myData = unidadOrganizacional;
}
And this is the part where I use the web service
- (void)viewDidLoad
{
// Do any additional setup after loading the view from its nib.
EWSEmpresaWebServiceSvc *service = [[EWSEmpresaWebServiceSvc alloc]init];
[service ConsultarUnidadesOrganizacionalesPorEmpresa:self action:#selector(ConsultarUnidadesOrganizacionalesPorEmpresaHandler:) EmpresaId:self.empresaID];
[super viewDidLoad];
}
And the tableview is empty. Why does this happen? How can I use the data and fill my tableview?
Try to change your code this way :
self.myData = [[NSMutableArray alloc] init]autorelease];
// your loop
[sel setMyData:unidadOrganizacional];
try loading it in a dictionary:
dict = [resp objectForKey:#"YourKey"];
if( ( dict == nil ) || ![dict isKindOfClass:[NSDictionary class]] ) {
NSLog( #"WARNING: %#", [dict description]);
return;
}
empID = [[dict objectForKey:#"empresaID"]copy];
NSLog(#"Your Value: %#", empID);
I found the answer, I just have to put
[_myTableView reloadData]
at the end of the method.

Resources