【问题标题】:AFNetworking and NSURLConnection on main thread主线程上的 AFNetworking 和 NSURLConnection
【发布时间】:2013-06-04 12:39:57
【问题描述】:

编辑:屏幕截图中突出显示的行是我遇到的问题,为什么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 会使用主线程?以及如何解决它。

【问题讨论】:

    标签: ios objective-c nsurlconnection afnetworking


    【解决方案1】:

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

    【讨论】:

    • 这是仪器屏幕截图中突出显示的部分,我对 +[NSURLConnection(loader) 等感兴趣,它位于 [NSThread main] 的箭头下方,这不是主线程吗?跨度>
    • 谢谢,我觉得我很困惑,并认为这是主线程
    【解决方案2】:

    这是因为 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.0 之前的 AFNetworking 中使用此代码并且崩溃了。
    【解决方案3】:

    编辑:

    这里是一些在后台线程中运行操作的代码。使用从 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
        }];
    }
    

    【讨论】:

    • 你没有回答女巫的问题:为什么 AFNetworking 会使用主线程?以及如何解决它。
    • 我进行了编辑以解释我的帖子背后的意图。希望这会有所帮助!
    • 谢谢,我知道如何在不同的线程上运行,我只是不明白为什么当我使用 AFNetworking 时,它调用 NSURLConnection 是在主线程上。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多