0

我想执行一项必须在后台运行的任务。该任务涉及解析 Web 服务的响应。由于需要一些时间,我希望它在后台运行。下面是我尝试执行后台任务的代码。

//**When a button is tapped this method will be called.**
dispatch_queue_t myQueue=dispatch_queue_create("My Queue",  NULL);

    dispatch_async(myQueue, ^{

        [self getDataPetioleGraph];//**This will parse the webservice response and the output will be stored in a array for populating on tableview**


        dispatch_async(dispatch_get_main_queue(), ^{


            [tableViewObj reloadData];
        });

    });

-(void)getDataPetioleGraph{

NSString *soapContent=[NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                       "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
                       "<soap:Body>"
                       "<GetDataPetioleGraph xmlns=\"http://tempuri.org/\">"
                       "<Account_Number>%@</Account_Number>"
                       "</GetDataPetioleGraph>"
                       "</soap:Body>"
                       "</soap:Envelope>",@"38003"];
NSMutableURLRequest *request=[[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:@"web service link is here"]] autorelease];
NSString *contentLength=[NSString stringWithFormat:@"%d",[soapContent length]];
[request addValue:@"text/xml" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"http://tempuri.org/GetDataPetioleGraph" forHTTPHeaderField:@"SOAPAction"];
[request addValue:contentLength forHTTPHeaderField:@"Content-Length"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[soapContent dataUsingEncoding:NSUTF8StringEncoding]];    
getDPGConnection=[[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
[getDPGConnection start];

但是当我点击调用上述函数的按钮时,什么也没有发生。我已经尝试了其他答案,但我仍然没有得到解决方案。谁能告诉我哪里出错了。提前致谢。

4

6 回答 6

1

由于NSURLConnection您使用的是异步的[self getDataPetioleGraph];,因此将立即返回,然后您UITableView将重新加载数据,而不会从 web 服务获取结果。

因此,一种方法是实现委托方法- (void)connectionDidFinishLoading:(NSURLConnection *)connection并在那里等待,直到从 Web 服务接收到所有数据,然后您可以开始在后台线程中解析 JSON 数据。

所以是这样的:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

     // Now your download has finished asynchronously, you can start to process the JSON
     dispatch_async(dispatch_get_global_queue(0, 0), ^{

        BOOL isJSONProcessed = [self processJSON];

        if (isJSONProcessed) {

            dispatch_async(dispatch_get_main_queue(), ^{

                [self.yourTableView reloadData];
            });
});
于 2013-07-17T08:24:10.427 回答
0

有很多方法可以做到这一点,包括 NSThread、NSOperation 和您使用的一种。这是一个简单的例子:

dispatch_queue_t jsonParsingQueue = dispatch_queue_create("parsingQueue", NULL);

// execute a task on that queue asynchronously
dispatch_async(jsonParsingQueue, ^{
    [self doYourJsonParsingAndReadingTask];
    //As once this done and you need to call any code in main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.viewController updateThingsWithNewData];
    });
});

// release the dispatch queue if ARC not enable
dispatch_release(jsonParsingQueue);
于 2013-07-17T07:42:41.057 回答
0

异步请求不需要后台线程。基本上,您正在做的是创建一个后台线程,然后发送一个异步请求,该请求正在创建另一个后台线程以获取您要求的数据,它将通过您需要实现的委托方法返回其结果。

上面代码片段的问题是您希望请求立即返回,但因为它是异步的,所以不会。

在这种情况下,这一切都可以通过主线程完成,因此您过于复杂了。

于 2013-07-17T08:29:16.160 回答
0

你有几种方法。

我喜欢使用 NSOperationQueues,因为它们提供了一个完成块,一旦您收到数据,您就可以在其中调用 UI 函数。

例子:

NSBlockOperation * op = [NSBlockOperation blockOperationWithBlock:^{
    [self getDataPetioleGraph];
}];

NSOperationQueue * opQueue = [[NSOperationQueue new] autorelease];
[op setQueuePriority:NSOperationQueuePriorityNormal];
[opQueue addOperation:op];
//Once we receive the neccesary data we populate the views with it in in the main thread
op.completionBlock = ^{
    dispatch_async(dispatch_get_main_queue(), ^{
       [tableViewObj reloadData];
    });
};
于 2013-07-17T07:41:22.403 回答
0

未调用您的委托(如果您完全实现了它们)的原因是您在与您的 queue 关联的未指定myQueue后台线程上启动连接。这个未指定的线程将没有运行循环。实际线程甚至可以针对分派到该队列的不同块而改变。

ANSURLConnection需要安排在

a) 具有运行循环的专用线程。或者

b) 一个NSOperationQueue

除非您明确指定连接对象的调度位置,否则连接的委托方法将在将方法发送到连接的同一线程上执行。start当这个线程没有运行循环时,您的委托将不会被调用。

案例a)可以如下实现:

在运行循环上调度 NSURLConnection

首先,确保您在专用线程上运行并确保该线程具有运行循环。这可以是主线程或您注意添加运行循环的任何其他线程。(后者比期望的更棘手,为简洁起见,我不在这里解释)。

创建NSURLConnection对象,确保它不会立即启动:

connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];

然后在当前线程/运行循环上安排连接并启动它:

[self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[self.connection start];

注意:这样,当前线程的运行循环将用于调度委托。不可能指定除当前线程之外的另一个线程!

现在使用NSOperationQueue将执行代表的地方:

在 NSOperationQueue 上调度 NSURLConnection

这实际上更简单。您只需要一个 NSOperationQueue 实例,然后按如下方式启动连接:

首先,创建NSOperationQueue将安排代表的实例:

self.queue = ...;  

创建NSURLConnection对象,确保它不会立即启动:

connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];

安排并开始连接:

[self.connection setDelegateQueue:self.queue];
[self.connection start];

以上将解决您的问题的一部分。它没有解释如何实现委托、保存响应数据的位置以及如何将冗长的解析操作分派到处理队列中。

这是 Gist 上的示例,它使用专用类SimpleGetHTTPRequest实现 GET 请求。您可能会发现这有助于实现您的 POST 请求。

于 2013-07-17T09:08:33.507 回答
-2

我认为NSOperationQueue应该可以工作。

于 2013-07-17T07:38:21.483 回答