主线程上的AFNetworking和NSURLConnection

时间:2013-06-04 12:39:57

标签: ios objective-c nsurlconnection afnetworking

enter image description here

编辑:屏幕截图中突出显示的行是我遇到的问题,为什么NSURLConnection[NSThread main]上运行时我没有调用它,AFNetworking是。

我正在为我的项目使用AFNetworking,但是当在Instruments中运行Time Profiler时,我在NSURLConnection的主线程上看到很多活动,我觉得这不是我想要的。

我的方法是

- (void)parseArticles {   
    NSMutableArray *itemsToParse = [[FMDBDataAccess sharedDatabase] getItemsToParse];

    NSMutableArray *operations = [[NSMutableArray alloc] init];


    for (Post *p in itemsToParse) {

        NSMutableString *strURL = [NSMutableString new];
        [strURL appendString:@"http://xxxxxxxxxxxxxxxxxxxxxx.php?url="];
        [strURL appendString:[p href]];

        NSURL *url = [NSURL URLWithString:strURL];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
        [[ParserClient sharedInstance] registerHTTPOperationClass:[AFHTTPRequestOperation class]];

        [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

            dispatch_async(loginParseQueue, ^{

                Parser *parse = [[Parser alloc] init];
                [parse parseLink:responseObject rowID:[p rowID]];
            });
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"%@",error);
        }];
        [operations addObject:operation];
    }
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    [operationQueue setMaxConcurrentOperationCount:3];
    [operationQueue addOperations:operations waitUntilFinished:NO];
}

为什么AFNetworking会使用主线程?以及如何解决它。

3 个答案:

答案 0 :(得分:4)

AFNetworking正在不在主线程中的子线程上运行,但每个线程都有一个main方法,该方法位于您发布的图像上。这不是主线。现在告诉我你想修复什么?

答案 1 :(得分:4)

这是因为AFNetworking使用“successCallbackQueue”来路由完成块:

AFHTTPRequestOperation.m:

self.completionBlock = ^{
    if (self.error) {
        if (failure) {
            dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{
                failure(self, self.error);
            });
        }
    } else {
        if (success) {
            dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{
                success(self, self.responseData);
            });
        }
    }
};

您可以简单地为成功和失败完成块分配不同的线程:

dispatch_queue_t backgroundQueue = dispatch_queue_create("com.name.bgqueue", NULL);
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.successCallbackQueue = backgroundQueue;
operation.failureCallbackQueue = backgroundQueue;

答案 2 :(得分:-2)

编辑:

以下是一些在后台线程中运行操作的代码。使用从UI线程调用的任何函数都将在UI线程上运行。您可以使用类似于下面指定的技术在后台线程上运行操作,然后将结果发送回UI线程供以后使用。

以下是我使用的技术,您可以使用AFHTTPRequestOperation替换我的sendSynchronousRequest调用:

指定一种特殊类型(块),以便您可以传递代码块。

typedef void (^NetworkingBlock)(NSString* stringOut);

然后,您需要调度到后台线程,以免冻结您的UI线程。

这是一个在后台线程中调用东西,然后等待响应的函数,然后在完成时调用一个块而不使用UI线程来执行它:

- (void) sendString:(NSString*)stringIn url:(NSString*)url method:(NSString*)method completion:(NetworkingBlock)completion {
    //build up a request.
    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    NSData *postData = [stringIn dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPMethod:method];
    [request setValue:[NSString stringWithFormat:@"%d", postData.length] forHTTPHeaderField:@"Content-Length"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];  //or whatever
    [request setHTTPBody:postData];

    //dispatch a block to a background thread using GCD (grand central dispatch)
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSURLResponse *response;
        NSError* error;

        //request is sent synchronously here, but doesn't block UI thread because it is dispatched to another thread.
        NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

        //call complete, so now handle the completion block.
        if (completion) {
            //dispatch back to the UI thread again
            dispatch_async(dispatch_get_main_queue(), ^{
                if (responseData == nil) {
                    //no response data, so pass nil to the stringOut so you know there was an error.
                    completion(nil);
                } else {
                    //response received, get the content.
                    NSString *content = [[NSString alloc] initWithBytes:[responseData bytes] length:responseData.length encoding:NSUTF8StringEncoding];
                    NSLog(@"String received: %@", content);

                    //call your completion handler with the result of your call.
                    completion(content);
                }
            });
        }
    });
}

像这样使用:

- (void) myFunction {
    [self sendString:@"some text in the body" url:@"http://website.com" method:@"POST" completion:^(NSString *stringOut) {
        //stringOut is the text i got back
    }];
}