如果您查看Apple 文档,他们会说:
等待
一个布尔值,指定当前线程是否阻塞,直到在主线程上的接收器上执行指定的选择器之后。指定 YES 来阻塞这个线程;否则,指定 NO 使该方法立即返回。如果当前线程也是主线程,并且您为此参数指定 YES,则消息将立即传递和处理。
因此,如果您从主线程调用此方法,那么它将立即执行。
但是,这样做真的没有任何意义。如果您在主线程上,并希望在getBooks
主线程上执行,那么只需执行以下操作:
-(void) viewDidLoad {
[super viewDidLoad];
[self 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
清理此后台运行循环:
CFRunLoopStop(CFRunLoopGetCurrent());
再次,旧代码,所以使用
@autoreleasepool {
}
对于弧。