[英]How can I wait for a NSURLConnection delegate to finish before continuing?
[英]How can I wait for a NSURLConnection delegate to finish before executing the next statement?
這一直很難搜索。 我發現了一個類似的問題, iOS 5等待代表完成,然后再填充表格嗎? ,但是可接受的答案是“刷新表格視圖”,這對我沒有幫助。 我發現的其他結果往往是在c#中。
我有一個從iPhone流到Wowza服務器的應用程序。 當用戶命中記錄時,我生成一個唯一的設備ID,然后將其發送到服務器上的PHP腳本,該腳本返回帶有配置設置(包括rtmp轉儲鏈接)的JSON文檔。
問題是,委托方法是異步的,但是我需要在我的- (IBAction)recordButtonPressed
方法的下一行代碼之前獲取配置設置,因為該代碼用於設置配置文件設置,然后根據這些設置進行記錄。
我意識到我可以讓NSURLConnection
在-recordButtonPressed
像我現在,然后繼續委托方法中設置代碼connectionDidFinishLoading
(或只是封裝設置和方法調用它從那里),但這是犧牲一致的設計,功能性和吮吸。
我是否可以發送給委托人一些簡單的waitUntilDelegateIsFinished:(BOOL)nonAsyncFlag
標志,以便進行從網絡提取數據的順序操作?
我意識到我可以像現在一樣在-recordButtonPressed中創建NSURLConnection,然后在委托方法connectionDidFinishLoading中繼續設置代碼(或者只是封裝設置和從那里調用的方法),但這會犧牲功能的一致性設計,吮吸。
您已經分析並理解了這種情況,並且已完美地描述了其可能的解決方案。 我只是不同意你的結論。 這種事情一直在發生:
- (void) doPart1 {
// do something here that will eventually cause part2 to be called
}
- (void) doPart2 {
}
您可以通過調用來玩各種游戲,以使其更加優雅和通用,但是我的建議是,不要與框架抗爭,因為您所描述的正是異步的本質。 (而且不使用在主線程同步的請求,因為該塊的主線程,這是一種禁忌。)
確實,在事件驅動的框架中,“等到”這一概念非常令人厭惡。
為什么不使用同步請求 ?
將您的異步NSURLConnection請求包裝在一個輔助方法中,該方法具有一個完成塊作為參數:
-(void) asyncDoSomething:(void(^)(id result)completionHandler ;
此方法應在NSURLConnectionDelegate
實現。 有關詳細信息,請參見下面的示例實現和注釋。
在其他地方,在您的操作方法中:
設置完成處理程序。 該塊將在主線程上進一步調度,然后執行任何適當的操作來更新表數據,除非結果為錯誤,在這種情況下,您應該顯示警報。
- (IBAction) recordButtonPressed
{
[someController asyncConnectionRequst:^(id result){
if (![result isKindOfClass:[NSError class]]) {
dispatch_async(dispatch_get_main_queue(), ^{
// We are on the main thread!
someController.tableData = result;
});
}
}];
}
方法asyncConnectionRequst:
的實現可以按以下方式工作:將該塊保存在一個ivar中。 在適當的時候用正確的參數調用它。 但是,使用塊作為隱喻或屬性會增加無意中引入循環引用的風險。
但是,有一種更好的方法:包裝器塊將立即分派到一個掛起的串行分派隊列中,該隊列作為一個ivar保存。 由於隊列已暫停,因此它們將不執行任何塊。 僅在恢復隊列之后,該塊才執行。 您可以在connectionDidFinish:
和connectionDidFailWithError:
恢復隊列(如下所示):
在您的NSURLConnectionDelegate中:
-(void) asyncConnectionRequst:(void(^)(id result)completionHandler
{
// Setup and start the connection:
self.connection = ...
if (!self.connection) {
NSError* error = [[NSError alloc] initWithDomain:@"Me"
code:-1234
userInfo:@{NSLocalizedDescriptionKey: @"Could not create NSURLConnection"}];
completionHandler(error);
});
return;
}
dispatch_suspend(self.handlerQueue); // a serial dispatch queue, now suspended
dispatch_async(self.handlerQueue, ^{
completionHandler(self.result);
});
[self.connection start];
}
然后在NSURLConnectionDelegate中,調度處理程序並恢復處理程序隊列:
- (void) connectionDidFinishLoading:(NSURLConnection*)connection {
self.result = self.responseData;
dispatch_resume(self.handlerQueue);
dispatch_release(_handlerQueue), _handlerQueue = NULL;
}
同樣,發生錯誤時:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
self.result = error;
dispatch_resume(self.handlerQueue);
dispatch_release(_handlerQueue), _handlerQueue = NULL;
}
還有更好的方法,但是涉及更多一些基本的幫助程序類,這些類處理異步體系結構,最終使您的異步代碼看起來像是同步的:
-(void) doFourTasksInAChainWith:(id)input
{
// This runs completely asynchronous!
self.promise = [self asyncWith:input]
.then(^(id result1){return [self auth:result1]);}, nil)
.then(^(id result2){return [self fetch:result2];}, nil)
.then(^(id result3){return [self parse:result3];}, nil)
.then(^(id result){ self.tableView.data = result; return nil;}, ^id(NSError* error){ ... })
// later eventually, self.promise.get should contain the final result
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.