0

我有一个带有方法(getAndPlaySong)的类,它从服务器获取文本文件,从文本中获取特定字符串,并使用字符串(URL)从服务器获取音乐文件。获取文本文件的第一个服务器调用很快,所以我同步实现了它。第二个需要更长的时间,我想在它发生时更新显示。

我希望该方法在继续之前等待异步请求完成。我尝试在 connectionDidFinishLoading 方法中放置一个 BOOL:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Succeeded! Received %d bytes of data",[_receivedData length]);
    [AppDelegate playAudioWithData: _receivedData];
    _dataIsReceived = YES; //BOOL

    // release the connection, and the data object
    [connection release];
    [_receivedData release];
}

然后在 getAndPlaySong 方法中放置一个 while 循环:

[self startRequest: correctSongURL]; starts the request asynchronously

while (!_dataIsReceived) {
    //do stuff
}

结果是应用程序在到达循环时挂起。循环永远不会终止,我永远不会得到“Succeeded ...”输出。我有点困惑,将不胜感激一些意见。

4

3 回答 3

2

我不想听起来粗鲁,但你所做的是最糟糕的事情。当然,该应用程序挂起,因为它有一个无限循环。即使循环最终终止,当它在循环中时你的应用程序被卡住了——如果用户试图在循环中间对你的应用程序做某事怎么办?您需要改变思维方式并学习如何将事件驱动编程与状态机一起使用。这就是 iOS 的范式,你必须埋头苦干,做一些阅读和学习,改变你思考和构建程序的方式。

在您提出请求后,您什么也不做,即您的代码片段中没有接下来的代码。相反,您的应用程序坐在那里什么都不做(但仍然响应)等待连接完成(当您的应用程序什么都不做时,操作系统已经代表您创建了一个线程并且连接代码正在其中执行,当它完成您的连接代码时需要通知其余代码已完成,例如,您可以通过委托或通过通知来执行此操作)。

这并不是它唯一需要坐下来等待的事情——如果用户点击屏幕会怎样?如果用户退出您的应用程序怎么办?如果……您的应用程序需要能够响应所有可能的事件并快速响应,连接只是它必须侦听和响应的又一个事件。如果它在一个循环中,它就不能这样做。

永远不要在这样的地方使用循环。

“我希望该方法在继续之前等待异步请求完成。” 不,你不会——你永远不能在带有 GUI 的应用程序中做这样的事情。该函数必须完成执行。您需要实现一个状态机,每个 iOS 都是一个状态机,应用程序委托是驱动状态机的主要内容,然后随着更多事件添加到程序中,您添加更多状态和状态之间的转换。

查看应用程序委托及其告诉您的代码应用程序进入前台或后台或内存不足情况等的方法。这是事件驱动编程,您需要扩展和构建该原则以考虑您的连接事件和任何其他事件。

对不起,如果我听起来有点苛刻。

于 2012-05-26T04:56:45.267 回答
1

您的应用程序挂在循环上,因为它是无限的。

在 iOS 上,NSURLConnectionDelegate 是在连接上接收到数据时获取回调并在完成时收到通知的方式。一切都应该通过委托异步完成。这就是在 iOS 上完成的方式。

流入的结果应存储在 didRecieveData 方法中的 NSData 对象中。

查看 NSURLConnectionDelegate 上的文档,但这里有一个大纲示例:

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
     int statusCode = [(NSHTTPURLResponse *)response statusCode];    
     if(statusCode == 404) {
         // Post notification and let concerned parties know something went wrong.
         [self cleanupConnection];
     }
     else if( statusCode == 200) {
         // Success do something with the data.
         requestData = [[NSMutableData alloc] init];
     }
     else {
         [self cleanupConnection];
     }
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [requestData appendData:data];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self finishedLoadingAppData];
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"Connection Attempt Failed with Error:%@", [error localizedDescription]);
}
于 2012-05-25T23:57:31.523 回答
0

想到两个快速选项: 创建一个方法来调用以处理完成的连接 使用 NSNotification API 在加载完成时发送通知

此外,您可以使用 NSURLConnection didReceiveData 的方法来处理来自服务器的增量数据。

于 2012-05-25T22:12:01.267 回答