我有tableview名称和状态。苹果推送通知(APNS)时状态改变。 但我有这个问题。如果没有通知,我该怎么办?或者,如果用户点击此消息的关闭按钮。 我尝试使用ASIHTTPRequest更新表:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
HomePageTableCell *cell = (HomePageTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
cell.nameLabel.text = [device valueForKey:@"name"];
if ([[device valueForKey:@"status"] isEqualToNumber:@1])
{
cell.status.text = @"Not configured";
cell.stav.image = [UIImage imageNamed:@"not_configured.png"];
}
if ([[device valueForKey:@"status"] isEqualToNumber:@2])
{
//some other states
}
return cell;
}
我尝试在加载单元格之前更改状态...
- (void) getStatus:(NSString *)serialNumber
{
NSURL *url = [NSURL URLWithString:@"link to my server"];
__block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
__weak ASIHTTPRequest *request_b = request;
request.delegate = self;
[request setPostValue:@"updatedevice" forKey:@"cmd"];
[request setPostValue:serialNumber forKey:@"serial_number"]; //get status of this serial number
[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
//here I want to change cell status in SQLite, but don't know how
//something with indexPath.row? valueForKey:@"status"???
}
}
}];
[request setFailedBlock:^
{
if ([self isViewLoaded])
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
ShowErrorAlert(@"Error", [[request_b error] localizedDescription]);
}
}];
[request startAsynchronous];
}
或者,如果没有苹果通知或者用户没有点击通知消息,那么更好的方法是在我的表视图中更改状态?感谢
编辑: 我不知道如何将数据存储到NSManagedObject *设备。你能帮帮我吗? 我试试这个,但它不起作用:(在你写的地方)
NSInteger statusInt = [status intValue]; //change to int value
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[device setValue:statusInt forKey:@"status"];
EDIT2: 我明白了,但问题在于重装表数据
NSString *responseString = [request_b responseString];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *result = [parser objectWithString:responseString error:nil];
NSString *status = [result objectForKey:@"status"];
NSInteger statusInt = [status intValue]; //change to int value
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[device setValue:statusInt forKey:@"status"]; //there is problem in save statusInt
// [device setValue:@ 5 forKey:@“status”]; //如果我这样做,那么状态是integer16类型
和第二个问题在于重载表数据。我把它放在那里
[self.tableView reloadData]
但它在循环中一次又一次地重装,出了什么问题?我的东西有无限循环,如果我没有重新加载表数据更改将在下一个应用程序加载中可见。我认为问题是我打电话
- (void) getStatus:(NSString *)serialNumber atIndexPath:(NSIndexPath *)indexPath
{}
in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
}
最好是在viewDidLoad或viewDidApper中,但我不知道如何为所有设备制作循环并调用
[self getStatus:[device valueForKey:@"serialNumber"] atIndexPath:indexPath];
在那个地方。
EDIT3:
如果我这样做会怎么样:
- (void)viewDidLoad
{
[self updateData];
[self.tableView reloadData];
}
-(void)updateData
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Device"];
request.returnsDistinctResults = YES;
//request.resultType = NSDictionaryResultType;
request.propertiesToFetch = @[@"serialNumber"];
NSArray *fetchedObjects = [self.managedObjectContext
executeFetchRequest:request error:nil];
NSArray *result = [fetchedObjects valueForKeyPath:@"serialNumber"];
//there I get all serialNumbers of my devices and than I call method getStatus and get "new" status and than update it in Core Data.
}
这是解决这个问题的好方法吗?如果我只调用一次getStatus方法并获得一系列状态,我认为会更好。
也许我可以将所有serialNubers设置在一个变量('xxx','yyyy','zzz')中,并在服务器上执行SELECT * FROM Devices WHERE serialNumber in(serialNuber)。
你认为这可行吗?我没有经验如何将数据从数组转换为字符串('array_part1','array_part2'....)
答案 0 :(得分:2)
您的代码在哪里拨打[UITableView reloadData]
?
一旦从服务器检索到新数据,就应该在tableview上调用reloadData
。由于您的服务器调用是异步的,服务器调用将在主线程继续时在单独的线程上运行,因此我假设您有以下问题...
- (void) ...
{
[self getStatus:@"SERIAL_NUMBER"];
[self reloadData]; // This will be called before the async server call above has finished
}
因此,您正在重新加载原始数据,因此可能在几秒钟后加载的新数据将不会显示。
要解决此问题,请调整[getStatus:]
方法以在服务器响应上调用[UITableView reloadData]
方法。
[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,我建议你研究AFNetworking。
<强>更新强>
针对您在设备statusInt
内设置NSManagedObject
时遇到的问题
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[device setValue:statusInt forKey:@"status"]; //there is problem in save statusInt
这是因为statusInt
是NSInteger
,它是主要数据类型,而不是NSObject
所期望的[NSManagedObject setValue:forKey:]
。从[NSManagedObject setValue:forKey:]的文档中,方法预期参数如下。
- (void)setValue:(id)value forKey:(NSString *)key
因此,在这种情况下,您需要传递NSNumber
。 NSInteger
的问题在于,对于基于当前系统的最大dynamic typedef
数据类型,它只是int
。从NSInteger
的实现中你可以看到抽象。
#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif
如果您当前的系统是64位,它将使用更大的long
数据类型。
现在,从技术上讲,服务器返回的status
值可以按原样存储,而不作为NSString
进行任何转换。当您需要检索并使用int
的主数据类型时,您可以使用已使用的[NSString intValue]
方法。
虽然最佳做法是使用NSNumberFormatter
,这对基于locale
的号码调整很有用,并确保不存在无效字符。
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"];
要在代码中使用int
时检索主数据类型,只需致电[NSNumber intValue]
。
NSNumber *statusNumber = [device objectForKey:@"status"];
int statusInt = [statusNumber intValue];
至于你在无限循环中遇到的问题,这是由[... getStatus:atIndexPath:]
内的调用reloadData
引起的,它包含方法调用[UITableView tableView:cellForRowAtIndexPath:]
。
这是因为reloadData
实际上会调用[UITableView tableView:cellForRowAtIndexPath:]
。
因此,您的代码将继续如下...
Initial UITableView data load -> tableView:cellForRowAtIndexPath: -> getStatus:atIndexPath: -> Server Response -> reloadData -> tableView:cellForRowAtIndexPath: -> getStatus:atIndexPath: -> Server Response -> reloadData -> ...
不幸的是,您无法强制更新一个单元格,您必须请求UITableView
使用reloadData
重新加载所有数据。因此,如果可能,您需要调整服务器以返回设备的唯一ID,以便您只能调整NSManagedObject
中的更新设备。
getStatus
方法的建议更改可能只是使用serialNumber
,如果它作为密钥存储在NSManagedObject
中。
- (void) getStatus:(NSString*)serialNumber