I am new in operation queue, so give me flexibility to ask that question which may ask already meanwhile I searched a lot but not able to find my desired solution.
I have a API which delete single document and its working fine via using AFNetworking(which take documentID as param and accesstoken). Now I want to delete multiples document the solution should be that I should have another API which takes array or string (comma separated).
As far as I know the solution should be to call that API into Loop and delete all, but I heard another solution which is NSOperationQueue. I saw tutorial but I am not able to use those in right manner.
Here below is my code to call one operation.
NSString *jsonString = #"";
NSString *authorizationValue = [self setAuthorizationValue:action];
NSString *language = #"en_US";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:language forHTTPHeaderField:#"Accept-Language"];
[request setValue:authorizationValue forHTTPHeaderField:#"authorization"];
//convert parameters in to json data
if ([params isKindOfClass:[NSDictionary class]]) {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:NSJSONWritingPrettyPrinted
error:&error];
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
[request setURL:[NSURL URLWithString:action]];
[request setTimeoutInterval:500.0];
[request setHTTPMethod:#"DELETE"];
NSMutableData *postBody = [NSMutableData data];
[postBody appendData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postBody];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
So kindly guide me how call this in operation queue, do I need to create these call and put into array and then add those into operation queue.
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
// Set the max number of concurrent operations (threads)
[operationQueue setMaxConcurrentOperationCount:3];
[operationQueue addOperations:#[operation] waitUntilFinished:NO];
Looking for your response.
Thanks
the solution should be that I should have another API which takes array or string (comma separated)
This would be the best solution, yes, because it minimise the workload of the client and the server and makes the smallest number of network requests possible - it's fast and efficient.
the solution should be to call that API into Loop and delete all, but I heard another solution which is NSOperationQueue
Using an operation queue is better than running in a loop because you have control over the timing (how many operations run concurrently), which you already show in your code.
The only issue with your code is calling NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; each time before adding the new operation. Instead of doing that you should create and configure the operation queue once and store a strong reference to it. Otherwise you have lots of different operation queues each executing operations concurrently and your setting of setMaxConcurrentOperationCount:3 means nothing.
Related
In my app have an array of dictionaries containing GPS logs (100 per dictionary). I have to post these dictionaries one at a time to a server. The problem I am having is not posting which works just wonderful with RestKit, it is that I have to post them in the same order as they are in the array. This is due to an index count in the dictionaries which shouldn't be messed up on the server and in the same order as in the array.
How can I post these objects using RestKit in a synchronous manner?
Here ist the code I am using currently (asynchronous):
for (int i = 0; i < [arrayOfGPSLogChunks count]; i++)
{
NSMutableDictionary *historyToUpload = [[NSMutableDictionary alloc] init];
[historyToUpload setObject:driveID forKey:#"driveID"];
[historyToUpload setObject:[arrayOfGPSLogChunks objectAtIndex:i] forKey:#"gpsLog"];
[[RKObjectManager sharedManager] postObject:nil
path:#"api/drives/addDriveChunk"
parameters:historyToUpload
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
RKLogInfo(#"Successfully Uploaded Drive Chunk %i/%i", i,arrayOfGPSLogChunks.count);
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
RKLogError(#"Failed Uploading Drive Chunk (%i): (Error: %#)", i, error);
}];
}
Update:
I tried using this method which does work just the ways I want it to but it blocks my whole UI thread:
for (int i = 0; i < [arrayOfGPSLogChunks count]; i++)
{
NSMutableDictionary *historyToUpload = [[NSMutableDictionary alloc] init];
[historyToUpload setObject:driveID forKey:#"driveID"];
[historyToUpload setObject:[arrayOfGPSLogChunks objectAtIndex:i] forKey:#"gpsLog"];
NSData *requestData = [NSJSONSerialization dataWithJSONObject:historyToUpload options:NSJSONWritingPrettyPrinted error:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kUploadDrivesChunkURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:kConnectionTimeOut];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] objectRequestOperationWithRequest:request success:nil failure:nil];
[operation start];
[operation waitUntilFinished];
if (operation.error)
{
...
}
}
Thanks a lot!
You should use NSOperationQueue to manage your server calls and setMaxConcurrentOperationCount to 1, like:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:1];
You can also take a look at this Link for further details.
You can set the operation queue of the object managers http client to have a max concurrent count of 1. Of you can use RestKit to do the mapping and then use something else to upload.
Arguably you should modify the server so that you send the objects and associated ordering information and then it doesn't matter what order they are received in (and this will remove numerous likely headaches in the future).
Been using AFNetworking 2.0 for the past two projects for a medium sized project to great success.
This one call though, to post a user' login info, keep failing on me (server states incorrect login & password, login is the email, we've check on the server and the values are the same I'm trying to send)
The server developer does not handle iOS / ObjC (java / mongoDB guy), All I'm giving is a URL and the parameters I need to pass with Content-Type = application/x-www-form-url-encoded
I read somewhere that characters such as # (in the email) could cause problems
Could anyone with more experience than me here chip in? my operation creation method is below, any help is TRULY appreciated.
-(AFHTTPRequestOperation *)loginUserWithParameters:(NSDictionary *)loginParameters
{
/*
parameters dictionary:
email
psw
deviceToken
*/
NSString *url=SERVER_USER_LOGIN;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:url]];
// [httpClient setParameterEncoding:AFFormURLParameterEncoding];
NSMutableURLRequest *request=[httpClient requestWithMethod:#"POST" path:nil parameters:nil];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:loginParameters options:kNilOptions error:nil];
[request setHTTPBody:jsonData];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[AFNetworkActivityIndicatorManager sharedManager].enabled=YES;
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
return operation;
}
Actually you say with your code that you will send url-encoded data to your server, but you are overriding the postBody of your request with custom data. So you should create your request with:
NSMutableURLRequest *request=[httpClient requestWithMethod:#"POST" path:nil parameters:loginParameters];
And you should delete below lines:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:loginParameters options:kNilOptions error:nil];
[request setHTTPBody:jsonData];
I think above changes will be enough.
I am trying to call a web service that is developed with ASP.NET. The purpose is to pass a username and password to the web service to simulate a log-in procedure.
In order to call the service i used the following method:
NSError *errorReturned = nil;
NSString *urlString = #"http:myDomain/myMethod?Operation=SignIn";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod: #"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:#"test" forKey:#"userName"];
[dict setObject:#"test" forKey:#"passWord"];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:&errorReturned];
[request setValue:[NSString stringWithFormat:#"%d", [jsonData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: jsonData];
NSURLResponse *theResponse =[[NSURLResponse alloc]init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&errorReturned];
if (errorReturned)
{
NSLog(#"%#", errorReturned);
}
else
{
NSString *retVal = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", retVal);
}
After running the app and clicking on the UIButton that fires the above method, nothing is shown in the console window.
The service returns the response in JSON format.
I want to know if i am missing something here since i am neither getting an error nor success log?
Any help would be appreciated!
Thank you.
Granit
A couple of thoughts:
If this method is getting called, you'd see something, even if retVal was empty and your
NSLog(#"%#", retVal);
just logged the app name and timestamp. Maybe change that NSLog to
NSLog(#"retVal = %#", retVal);
to remove any ambiguity. Or put in breakpoints in your code and single step through it to see what path the app takes.
Are you confident of your server interface? For example, is it possible that the Operation value of SignIn belongs in the JSON request, itself? Also, some services are case sensitive, so you might want to check that, too.
I don't know what access you have to the server, but it would be worthwhile to check the logs to make sure the request was received, possibly temporarily adding some logging within the code so you can confirm that the parameters were all received properly. Or, if nothing else, make sure that the server properly logs/reports any errors.
BTW, your instantiation of theResponse is unnecessary, and should just be
NSURLResponse *theResponse = nil;
The sendSynchronousRequest call doesn't populate an existing NSURLResponse instance, but rather creates a new instance and updates theResponse to point to it.
You should fix your request first, but you probably want, at the very least, to change this to use sendAsynchronousRequest instead of sendSynchronousRequest. You should never do synchronous calls on the main thread.
I solved my issue by using ASIHHTPRequest. Also i checked the server interface and it turned out that the parameters had to be sent with the URL.
-(void)signInAction:(id)sender{
NSURL *url = [NSURL URLWithString:#"http://mydomaain.com/UserService/SignIn/test/test"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDidFinishSelector:#selector(requestCompleted:)];
[request setDidFailSelector:#selector(requestError:)];
[request setDelegate:self];
[request setRequestMethod:#"GET"];
[request startAsynchronous];
}
- (void)requestCompleted:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
//[responseString UTF8String];
NSLog(#"ResponseString:%s",[responseString UTF8String]);
}
- (void)requestError:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"Error:%#",[error description]);
}
I've been reading over code samples and posts for days but I haven't found a definitive way to post JSON data from my Core Data objects to a RESTful web service. There's a TON of documentation about pulling the JSON from a web service but not so much about sending stuff back. Can anyone point me to a good example or post some code on how to do it? I'm using Core Data and I have the object I want to send back mapped to a Dictionary but I'm missing the code to send it to the service.
EDIT:
I ended up with the code below which looks right and runs without errors, but I get 0 bytes of data returned and my webservice doesn't seem to be receiving the request. The JSON data looks good, the URL is correct, and I can hit the webservice and get JSON data back from it. The NSURLConnection delegate methods also fire as expected.
Is there anything I'm missing below?
- (void)SubmitSystems
{
NSFetchRequest * allSystems = [[NSFetchRequest alloc] init];
[allSystems setEntity:[NSEntityDescription entityForName:#"System" inManagedObjectContext:self.managedObjectContext]];
NSError * error = nil;
NSArray * systems = [self.managedObjectContext executeFetchRequest:allSystems error:&error];
//error handling goes here
//for (NSManagedObject * system in systems) {
NSManagedObject *system = systems[2];
NSString *entityString = #"System";
NSString * serverString = [NSString stringWithFormat:#"%#%#", kWebServiceAddress, entityString];
NSURL *url = [NSURL URLWithString:serverString];
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:[self jsonSystemDictionary:(System *)system] options:kNilOptions error:&error];
//NSLog([[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]); //debug only
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval: 30.f];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [jsonData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: jsonData];
self.urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//}
}
You're going to need to NSMutableURLRequest. Using this, you can use setHTTPMethod and pass it the #"POST" string, and then use the attributes of your NSManagedObject to populate the URL, HTTPBody and/or HTTPHeader as needed.
I'm sure I'm dense from being new to iOS programming, but, I am having problems with AFNetworking. Specifically, when I use it, nothing happens. I don't get any response from the server, but, I also don't get any errors. All of the properties end up NULL.
Here is my request:
NSMutableDictionary *requestArray = [NSMutableDictionary new];
[requestArray setObject: #"getBio"
forKey: #"action"];
[requestArray setObject: #"1"
forKey: #"bioID"];
NSError * error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:requestArray options:0 error:&error];
NSString *myRequestString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [ [ NSMutableURLRequest alloc ] initWithURL: [ NSURL URLWithString: #"http://localhost/LP/JSON/Secure/bio.php" ] ];
[ request setHTTPMethod: #"POST" ];
[ request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
[ request setHTTPBody: [myRequestString dataUsingEncoding:NSUTF8StringEncoding]];
This seems to work as I get my expected result if I simply pass the request into a UIWebView or if I use this:
NSURLResponse *response;
NSError *err;
NSData *returnData = [ NSURLConnection sendSynchronousRequest: request returningResponse:&response error:&err];
NSString *content = [NSString stringWithUTF8String:[returnData bytes]];
NSLog(#"responseData: %#", content);
In other words, the POST is successful and JSON is returned.
But, none of these do anything (no error, no response):
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Data: %# %#", [JSON valueForKeyPath:#"firstName"], [JSON valueForKeyPath:#"lastName"]);
} failure:nil];
Nor does even the bare bones attempt work:
AFURLConnectionOperation *operation = [[AFURLConnectionOperation alloc] initWithRequest:request];
Obviously, I'm doing something horribly wrong. But, the silent failures are making this hard to figure out.
Thanks for any help.
EDIT:
Nevermind.. I am dense.
Wasn't creating the NSOperationQueue.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
Although, I'm still unclear why the properties aren't getting set. But, it looks like I at least have data.
Creating the request operation object does not automatically kick off the request. Like you pointed out in your edit, it's up to you to either enqueue it into an NSOperationQueue or do [operation start] manually.
I would recommend that you communicate with your server using AFHTTPClient, since that provides a built-in mechanism to correctly set either your query string or HTTP body based on parameters you pass in. See the Gowalla API example client in the sample code, and the method AFHTTPClient -postPath:parameters:success:failure.