AFNetworking and NSURLConnection on the main topic

enter image description here

EDIT: the highlighted line in the screenshot is what I came across, why NSURLConnection works on [NSThread main] , when I don't call it, AFNetworking is.

I use AFNetworking for my project, but when I run Time Profiler in the tools, I see a lot of activity in the main thread for NSURLConnection, I feel like this is not what I want.

My method

 - (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]; } 

Why will AFNetworking use the main thread? and how to fix it.

+4
source share
3 answers

AFNetworking does not work on the child stream in the main stream, but each stream has a main method, which is located in the image that you publish. This is not the main thread. Now tell me what you want to fix?

+4
source

This is because AFNetworking uses "successCallbackQueue" to route the completion block:

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); }); } } }; 

You can simply designate another thread for success and completion completion blocks:

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

EDIT:

Here is some code to start operations in the background thread. Using any function called from the user interface thread will work in the user interface thread. You can use a technique similar to the one described below to start your operation in the background thread, and then send the result back to the user interface thread for later use.

Here is the technique I used, you can replace my sendSynchronousRequest request with your AFHTTPRequestOperation :

Specify a special type (block) so that you can pass blocks of code.

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

Then you need to send the background thread so as not to freeze the UI thread.

Here you can call the material in the background thread, and then wait for an answer, and then call the block when it is executed without using the user interface thread to do this:

 - (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); } }); } }); } 

Use it as follows:

 - (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 }]; } 
-2
source

Source: https://habr.com/ru/post/1484400/


All Articles