[英]UITableView not responding to performSelectorOnMainThread
我设置了一个UITableView,它应该在从网站加载某些数据后显示一些信息。 为了更新UI和完成加载的数据,我使用了以下方法:
performSelectorOnMainThread:@selector(getBooks) withObject:nil waitUntilDone:YES
-(void)getBooks{
NSMutableString *theURL = [[NSMutableString alloc] initWithString:@"theURL"];
[theURL appendFormat:@"&UserID=%@", _appDel.userID];
NSLog(@"%@\n", theURL);
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:theURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData = [NSMutableData data];
} else {
// Inform the user that the connection failed.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"An Error Occured" message:@"Couldn't make a connection to the server. Please make sure your internet connection is on." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alert show];
}
但是,当我运行它时程序继续执行,虽然我将waitUntilDone设置为YES。 我的印象是waitUntilDone会等待选择器,直到它完成执行。 任何人都可以解释可能出现的问题吗? 谢谢你的帮助。
如果您查看Apple文档 ,他们会说:
等待
一个布尔值,指定当前线程是否阻塞,直到在主线程上的接收器上执行指定的选择器之后。 指定YES以阻止此线程; 否则,指定NO以使此方法立即返回。 如果当前线程也是主线程,并且为此参数指定YES,则会立即传递和处理消息。
因此,如果从主线程调用此方法,则会立即执行。
但是,这样做真的没有意义。 如果你在主线程上,并希望在主线程上执行getBooks
,那么就这样做:
-(void) viewDidLoad {
[super viewDidLoad];
[self getBooks];
}
如果您向我们展示了您在getBooks
实际所做的getBooks
,我们可能会提供更多帮助。 例如,如果getBooks
正在发出远程HTTP请求,要获取在线图书数据,那么您根本不想使用performSelectorOnMainThread:
. 您希望在后台线程上运行该操作,然后只有在网络请求完成后才回调主线程以更新您的UI。
更新:
有很多方法可以检索Web内容。 如果您要直接使用NSURLRequest
,那么您应确保此类实现NSURLConnectionDelegate
协议:
@interface MyViewController: UIViewController<NSURLConnectionDelegate> {
然后根据Apple示例实现其方法
- (void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *) response
{
// this method is called when the server has determined that it
// has enough information to create the NSURLResponse
// it can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
[receivedData setLength:0];
}
- (void) connection:(NSURLConnection *) connection didReceiveData:(NSData *)data
{
// append the new data to the receivedData
[receivedData appendData:data];
}
- (void) connection:(NSURLConnection *) connection didFailWithError:(NSError *) error
{
// release the connection, and the data object
[connection release];
[receivedData release];
// inform the user
UIAlertView* netAlert = [[UIAlertView alloc] initWithTitle:@"" message:@"Oops!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[netAlert show];
[netAlert release];
}
- (void) connectionDidFinishLoading:(NSURLConnection *) connection
{
if ([receivedData length] > 0) {
// do something with the data, and then tell the UI to update
[self performSelectorOnMainThread: @selector(updateUI) withObject: nil waitUntilDone: NO];
}
// release the connection, and the data object
[connection release];
[receivedData release];
receivedData = nil;
}
-(void) updateUI {
[tableView reloadData];
someLabel.text = @"New Status";
// whatever else needs updating
}
注意:上面的代码是在ARC引入之前编写的。 如果您的项目使用ARC,则需要使用release
调用删除所有这些行。 但是,建议您确保正确保留所receivedData
,因为您将在多个呼叫中使用它。
另一个注意事项: NSURLConnection
可以多种方式使用。 它可以同步使用,也可以异步使用。 并且,您始终可以决定启动它的线程。 如果你保留这个:
-(void) viewDidLoad {
[super viewDidLoad];
[self getBooks];
}
然后连接将在主线程上启动。 但是,它仍然是一个异步操作。 换句话说,在网络请求完成之前,它不会阻止viewDidLoad
。 但是,如果用户在下载发生时(如滚动)将要对UI执行任何重要操作,那么您可能会发现UI的响应性降低。 如果是这种情况,您可能要么这样做 ,要么强制网络操作到后台线程。 要做到这一点,请启动它:
-(void) viewDidLoad {
[super viewDidLoad];
[self performSelectorInBackground: @selector(getBooksInBackground) withObject: nil];
}
然后,我上面的NSURLConnectionDelegate
代码的唯一问题是后台线程将不会活得足够长,以通过您的委托回调传递响应。 为了保持活力,
-(void) getBooksInBackground {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[self getBooks];
CFRunLoopRun(); // Avoid thread exiting
[pool release];
}
然后,您必须将此调用添加到connectionDidFinishLoading
和connection:didFailWithError
以清除connection:didFailWithError
运行循环:
CFRunLoopStop(CFRunLoopGetCurrent());
再次,旧代码,所以使用
@autoreleasepool {
}
对于ARC。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.