I create a background thread to do a series of AFNetworking requests, and I want them to be in order. Some code:
dispatch_queue_t request_queue = dispatch_queue_create("someLabel", NULL);
dispatch_async(request_queue, ^{
dispatch_semaphore_wait(self.mySemaphore, DISPATCH_TIME_FOREVER);
// AFnetworking request I want to be synchronous
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"foo": #"bar"};
[manager POST:#"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
...
How do I make the AFHTTPRequest synchronous?
Thanks!
In this case, you should generate the NSURLSessionDataTask yourself. The AF Operation manager will enqueue the operation immediately (that's just what it does). If you create one yourself, you can call resume when you please or add the operation to your own queue as you please.
Related
Anyone know. how can make service call during user interacts with particular screen. I mean I need to call additional data while user interact with app. but it still look like device is hang. help me please.
For Get request use this code
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:#"http://example.com/resources.json" parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
or
NSURL *URL = [NSURL URLWithString:#"http://example.com/resources/123.json"];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:URL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
As you have not mentioned any code snippet, I assume that you are performing all your operations on main thread and that is the reason why your app is hanging. To be specific about main thread and background thread, we perform all the UI related tasks on main thread and background tasks on some other thread.So you can create another thread for your background task like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform your background task here
});
I have a few requests that needs to fire one by one while depending on the previous response.
That was pretty straight forward with NSOperation and trying to figure out
what's the best approach here with Sessions & AFNetworking >= 3.0
-(void)startGet
{
NSString *urlStr = [NSString stringWithFormat:#"https://test.com/test?%ld",(long)test];
NSURL *URL = [NSURL URLWithString:urlStr];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSLog(#"NUMBER: %ld",(long)test);
[manager GET:URL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"task: %#",task.currentRequest.URL.absoluteString);
} failure:^(NSURLSessionTask *operation, NSError *error) {
//NSLog(#"Error: %#", error);
}];
}
- (void)viewDidLoad {
[super viewDidLoad];
for (int i=0; i<10; i++)
{
test = i;
[self startGet];
}
}
The log I want to get is:
https://test.com/test?0
https://test.com/test?1
https://test.com/test?2
https://test.com/test?3
https://test.com/test?4
https://test.com/test?5
https://test.com/test?6
...
Things I've tried:
...
dispatch_group_t serviceGroup = dispatch_group_create();
...
-(void)startGet
{
NSString *urlStr = [NSString stringWithFormat:#"https://test.com/test?%ld",(long)test];
NSURL *URL = [NSURL URLWithString:urlStr];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSLog(#"NUMBER: %ld",(long)test);
dispatch_group_enter(serviceGroup);
[manager GET:URL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"task: %#",task.currentRequest.URL.absoluteString);
dispatch_group_leave(serviceGroup);
} failure:^(NSURLSessionTask *operation, NSError *error) {
dispatch_group_leave(serviceGroup);
//NSLog(#"Error: %#", error);
}];
dispatch_group_wait(serviceGroup,DISPATCH_TIME_FOREVER);
}
Although the request came out in the right order I would still get mixed responses like so:
https://test.com/test?4
https://test.com/test?7
https://test.com/test?1
https://test.com/test?3
I'm not sure if something is wrong with the code or I totally misunderstood the purpose of dispatch_group_t in that case.
I've digged around and saw a comment by matt from AFNetworking about integrating a simple solution using Operations & session in AF and it is soon to be public but it was over 2 years ago.
I'm trying to solve this without using nested requests or NSOperations
Thanks
You can try out 2 approaches
Semaphore
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSLog(#"NUMBER: %ld",(long)test);
[manager GET:URL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
dispatch_semaphore_signal(semaphore);
NSLog(#"task: %#",task.currentRequest.URL.absoluteString);
} failure:^(NSURLSessionTask *operation, NSError *error) {
//NSLog(#"Error: %#", error);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
WaitUntillFinished
[operation waitUntilFinished];
You can check for detailed implementation at below link:
https://github.com/AFNetworking/AFNetworking/issues/1804
I am trying to write unit test for my project which I use AFNetworking in.I use the following operation for my request:
- (void)testRegisterRequest{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:url parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
XCTAssert(Result,"Register failed!");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//Failure
}
As it is asynchronous it never test my XCTAssert line.
I searched a lot but I couldn't manage to find a tutorial or example for these test cases.Please help me by any tutorial link or hint.
Thanks in advance
There are a couple of things here.
You can use expectations for async tests: Asynchronous Testing With Xcode 6
You can use OHHTTPStubs to avoid unneeded network traffic and server load: Usage Examples
XCTestExpectation is a valid approach. Other testing frameworks offer different ways. For example, we can test a success response using OCHamcrest like this:
- (void)testRegisterRequest
{
__block id response = nil;
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:url parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
response = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
assertWithTimeout(5, thatEventually(response), is(notNilValue()));
}
You would probably test the response for its attributes, instead of simply testing that it is not a nil value.
AFNetworking was offering the outputStream property for AFHTTPRequestOperation. Right now I'm changing to AFURLSessionManager and I want to keep my logic but I don't know if it's possible.
Old logic (simplified):
- (AFHTTPRequestOperation*)doRequestWithOutputSteam:(NSOutputStream*) outputStream
{
AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperation* operation = [manager GET:#"http://example.com/file/to/download"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error.localizedDescription);
}];
if (outputStream)
{
operation.outputStream = outputStream;
}
return operation;
}
I'm using this function because I'm streaming the data directly to another device. I don't want to wait until the download is finished and then stream the data to the device. I want to stream it while the data is received.
Question:
Is there a way to keep the behaviour while using AFURLSessionManager and NSURLSession?
I was using AFNetworking to deal with the http request.And here is my code:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:URL_LOGIN parameters:parames success:^(AFHTTPRequestOperation *operation, id responseObject) {
[self.tableview reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Request failed");
}];
or:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:URL_LOGIN parameters:parames success:^(AFHTTPRequestOperation *operation, id responseObject) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableview reloadData];
});
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Request failed");
}];
Which one is right,does it necessary to use dispathc_get_main_queue(),or the AFNetworking fix everything? Anybody knows?Thanks in advance.
On one hand, AppKit and UIKit is not thread safe, so you have to do any UI-related work on the main thread.
But as for AFNetworking, it automatically makes sure that the callbacks (success or failure) is executed on the main thread (unless you set otherwise). So normally you do not have to explicitly use dispatch_get_main_queue to dispatch your work to the main thread.
To check whether the callback is on the main queue:
[manager POST:someURL parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (operation.completionQueue == NULL) {
// is main queue
}
}...
Documentation
UI update always happens in main thread.So your tableview needs to be reloaded in main thread.
So the second one is true.