为什么使用 NSURLConnection sendAsynchronousRequest 建立与数据库的连接会延迟?

Why is there a delayed in establishing a connection to a database using NSURLConnection sendAsynchronousRequest?

对不起,我不知道这个,但我想知道为什么我尝试建立与数据库的连接时会出现延迟。

我基本上是从数据库中提取数据以将信息显示回 UITableView,但连接建立似乎有延迟。

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self fetchFromDatabase];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    [self fetchFromDatabase];
    
    NSLog(@"FOUR");
}

- (void)fetchFromDatabase
{
    // The URL of the database
    NSURL *url = [[NSURL alloc] initWithString:SDTET_DATABASE_SCHEDULE];
    
    // Establish the connection to the database
    [NSURLConnection sendAsynchronousRequest:[ [NSURLRequest alloc] initWithURL:url] queue:[ [NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
     {
         NSLog(@"ONE !");
     } ];
}

然而,输出看起来像这样:

FOUR

FOUR

ONE !

为什么 ONE ! 没有先打印出来?

如果可能,如何确保在调用 numberOfSections 之前发生连接?

谢谢

这是因为它是一个异步请求(意味着它不一定立即发生)。这是计算机科学的一个重要原则,它是一个比 Objective-C 或 iOS 开发更大的概念。

在您的情况下,您可以摆脱在 numberOfSectionsInTableView: 中调用的提取,而只需在 completionHandler 中调用 [self.tableView reloadData]

因为网络访问速度慢,所以有延迟。有时真的很慢。

有时您可以在不到一秒的时间内收到回复,而有时您可能需要一分钟的大部分时间才能收到回复。

您应该始终将您的网络代码编写为异步的,这意味着您使用 return 立即提交请求的方法。您的程序继续 运行,然后在收到响应后您会收到通知。

您的代码就是这样。

您不想发送在 numberOfSectionsInTableView 中加载数据的请求。您应该尽早发送网络请求,最好在显示结果的视图控制器显示之前发送。

但是,在您有数据填充之前显示 table 视图是很常见的。您可能会显示一个空的 table 视图,其中包含数据正在加载的消息或进度对话框。在其他情况下,您可能知道要显示多少个单元格,并且有文本数据但没有图像。在这种情况下,您可以使用占位符图像填充您的单元格。加载数据后,您可以更新显示。

在您的情况下,您应该将 numberOfSectionsInTableView 和 numberOfRowsInSection: 方法写入 return 零,然后使网络调用的完成方法告诉 table 视图重新加载自身。

ONE 最后打印,因为您正在调用异步方法。

您可以按照程序的流程进行操作(哪个方法按什么顺序调用哪个)。如果我们想象一下,我们可以说当一个方法是同步的时候,它基本上"says"到下一行代码等待它(方法)完成。 但是,如果一个方法是异步的,它会说 "don't wait for me"。您使用的 URL 请求方法是异步的。这意味着它开始做它的工作但没有人等待,代码的执行在下一行立即

拼图中有一块可以进一步阐明这一点。请求方法需要提供一个 完成块 作为参数。解释块超出了此处的范围,但您需要了解块是什么才能完全掌握问题的解决方案。 可以这么说,一旦这个异步方法完成它的工作(这可能会很长时间,this 确实是异步方法的原因之一),该块将被调用并执行。

因此,要回答您的最后一个问题,您需要触发 table 视图的刷新,您可以通过调用 [self.tableView reloadData]; 街区内。这里有一个很好的逻辑,因为您知道块仅在异步方法完成其工作后才执行,您将刷新 table 视图,知道您有来自 db 的更新数据。