Where in your code do you call [UITableView reloadData]
?
You should call reloadData
on your tableview once you have retrieved the new data from the server. As your server call is async the server call will run on a separate thread while the main thread continues, therefore I presume you have the following problem...
- (void) ...
{
[self getStatus:@"SERIAL_NUMBER"];
[self reloadData]; // This will be called before the async server call above has finished
}
Therefore you are reloading the original data and therefore the new data, which may have loaded a few seconds after, wont be shown.
To fix this, adjust the [getStatus:]
method to call the [UITableView reloadData]
method on server response.
[request setCompletionBlock:^
{
if([self isViewLoaded])
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
if([request_b responseStatusCode] != 200)
{
ShowErrorAlert(@"Comunication error", @"There was an error communicating with the server");
}
else
{
NSString *responseString = [request_b responseString];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *result = [parser objectWithString:responseString error:nil];
status = [result objectForKey:@"status"];
NSInteger statusInt = [status intValue]; //change to int value
// Store the server response in NSManagedObject *device,
// which will be used as the data source in the tableView:cellForRowAtIndexPath: method
// Once stored, check the tableview isn't NULL and therefore can be accessed
// As this call is async the tableview may have been removed and therefore
// a call to it will crash
if(tableView != NULL)
{
[tableView reloadData];
}
}
}
}];
ASIHTTPRequest is also no longer supported by the developers, I suggest you look into AFNetworking.
Update
In response to the problem you are now having with setting the statusInt
within the device NSManagedObject
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[device setValue:statusInt forKey:@"status"]; //there is problem in save statusInt
This is caused as statusInt
is an NSInteger
which is a primary datatype and not an NSObject
as expected by [NSManagedObject setValue:forKey:]
. From the documentation for [NSManagedObject setValue:forKey:], the methods expected parameters are as follows.
- (void)setValue:(id)value forKey:(NSString *)key
Therefore you need to pass, in this case, an NSNumber
. The problem with NSInteger
is that it's simply a dynamic typedef
for the largest int
datatype based on the current system. From NSInteger
's implementation you can see the abstraction.
#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif
If your current system is 64-bit it will use the larger long
datatype.
Now, technically the returned status
value from the server can be stored as it is without any conversion as an NSString
. When you need to retrieve and use the primary datatype of int
you can use the [NSString intValue]
method you have already used.
Although it's best practice to use a NSNumberFormatter
which can be useful for locale
based number adjustments and ensuring no invalid characters are present.
NSString *status = [result objectForKey:@"status"];
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
NSNumber * statusNumber = [f numberFromString:status];
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[device setValue:statusNumber forKey:@"status"];
To retrieve the primary datatype when you wish to use the int
within your code, simply call the [NSNumber intValue]
.
NSNumber *statusNumber = [device objectForKey:@"status"];
int statusInt = [statusNumber intValue];
As for the problem you are having with the infinite loop, this is caused by called [... getStatus:atIndexPath:]
, which contains the method call reloadData
, from within [UITableView tableView:cellForRowAtIndexPath:]
.
This is because reloadData
actually calls [UITableView tableView:cellForRowAtIndexPath:]
.
Therefore your code continuously goes as the following...
Initial UITableView data load -> tableView:cellForRowAtIndexPath: -> getStatus:atIndexPath: -> Server Response -> reloadData -> tableView:cellForRowAtIndexPath: -> getStatus:atIndexPath: -> Server Response -> reloadData -> ...
Unfortunately you cant just force one cell to update, you have to request the UITableView
to reload all data using reloadData
. Therefore, if possible, you need to adjust your server to return an unique ID for devices so you can adjust only the updated device within your NSManagedObject
.
A suggested alteration for the getStatus
method could be just to use the serialNumber
if this is stored within the NSManagedObject
as a key.
- (void) getStatus:(NSString*)serialNumber