breaking up an API connection call into functions Objective-C - objective-c

This most likely a very trivial questions but I have a connection set up to an API in order to retrieve information. Right now I have everything setup in viewDidLoad. I know there is a more efficient way to place this information for later access by the user but I am too inexperienced in Objective-C to know how to do it. Here is how I have it all laid out at the moment.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.myurl.com"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSData *myResponse = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
NSString *myString = [[NSString alloc] initWithData:myResponse encoding:NSUTF8StringEncoding];
SBJsonParser *myParser = [[SBJsonParser alloc] init];
NSArray *myData = [parser objectWithString:myString error:nil];

Try this:
- (void)loadAndParseURL:(NSString *)URLString
completion:(void (^)(NSArray *data))completion {
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:URLString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
dispatch_async(dispatch_get_global_queue(DISPATH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *myResponse = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
NSString *myString = [[NSString alloc] initWithData:myResponse encoding:NSUTF8StringEncoding];
SBJsonParser *myParser = [[SBJsonParser alloc] init];
NSArray *myData = [parser objectWithString:myString error:nil];
completion(myData);
});
}
completion is a block (anonymous function pointer), which accepts an array as parameter and executes customized code blocks. The block holds the value of local variables, aka the 'environment', and evaluates its content at the time of execution(, usually with delay of some kind), in this example, after myData is parsed from myString. dispatch_async puts the anonymous block that sends the request and does other stuff onto a background queue (in a background thread, of course). So the calling to this method is returned before the response is even received, and you should arrange anything after within the completion block.

If spinning it off into a thread is what you are looking for I would use sendAsynchronousRequest
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:URLString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSString *myString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
SBJsonParser *myParser = [[SBJsonParser alloc] init];
NSArray *myData = [parser objectWithString:myString error:nil];
// Do what you want with the response and subscribe
//anywhere in your code to get notified when it completed.
[[NSNotificationCenter defaultCenter]
postNotificationName:#"NotifyMeWhenDone"
object:self];
}];

Related

How to send json data in the Http request to POST Method in JSON Parsing

I need to Parse below string to POST method in iOS
"jsonData":{"empId":"cxvd","password":"sfsd"}
But I m getting the error as
Res: Tomcat Error
HTTP Status 400 - Required String parameter 'jsonData' is not present
//------ Method I have used to Parse is ---------- //
+(void) requestToServerForLogin:(NSString*)userName andPassward: (NSString*)password onCompletion:(RequestCompletionHandler) handler
{
NSString *url = [Ip stringByAppendingString:#"login"];
NSString *jsonString = [NSString stringWithFormat:#"\"jsonData\":{\"empId\":\"%#\",\"password\":\"%#\"}",
userName,
password ];
NSURL *nsurl = [NSURL URLWithString:url];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:nsurl];
[urlRequest setTimeoutInterval:60.0f];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setValue:#"application/json"
forHTTPHeaderField:#"Content-type"];
NSString *body = jsonString1;
[urlRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"urlRequest :%#",[body dataUsingEncoding:NSUTF8StringEncoding]);
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data1, NSError *error)
{
NSString *res = [[NSString alloc] initWithData:data1 encoding:NSUTF8StringEncoding];
if(handler) handler(res,error);
}];
}
Thanks in advance
There is way to much code. The substringToIndex and substringFromIndex are wrong, should not be in the code.
Use the literal syntax for the dictionaries:
NSDictionary *jsonDict = #{#"jsonData":#{#"password":password, #"empId":userName}};
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonDict options:0 error:&error];

NSURLConnection and pointer types bug

Here the problem, i'am using a http request, but when i use NSURLConnection to get my xml file and set a NSString *xml variable with that xml file i get a block pointer error if i return it. But if i take NSString *xml and send it to a method it tells me nothing and the xml variable is well set. Also if i return at the end of my method the variable, i get a nil at the parent calling method. How can i fix this because the return of the variable is needed. Thanks for any help, and here is my code :
The error :
incompatible block pointer types sending 'NSString *(^)NSURLResponse *, NSData *, NSError *)'to parameter of type 'void(^)(NSURLResponse *,NSData *, NSError *)'
- (NSString *)restTestRequester: (NSString *)uriRequested serviceUri:(NSString *)sUri parameters:(NSString *)uriParameters technique:(NSString *)requestTechnique {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *l_api_key = [prefs stringForKey:#"globalPublicK"];
NSString *l_secret_key = [prefs stringForKey:#"globalSecretK"];
l_uri = [NSString stringWithFormat:#"%#/%#", uriRequested, sUri];
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:l_uri]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
[theRequest setHTTPMethod:requestTechnique];
[theRequest setValue:#"application/xml" forHTTPHeaderField:#"Accept"];
[theRequest setValue:#"application/x-www-form-unrlencoded" forHTTPHeaderField: #"Content-Type"];
[theRequest setValue:l_api_key forHTTPHeaderField: #"EMApikey"];
[theRequest setValue:[self hmacsha1:l_uri secret:l_secret_key] forHTTPHeaderField: #"EMRequestHash"];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if( theConnection )
{
[NSURLConnection sendAsynchronousRequest:theRequest
queue:[NSOperationQueue mainQueue]
incompatible block pointer types error--> completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
here ---->xml = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]
autorelease];
works--->[self myMethod:xml];
doesn't work---> return(xml);
}
];
}
else
{
NSLog(#"theConnection is NULL");
}
[theConnection release];
equals nil variable returned-->return xml;
}
I think that the problem is in async call, U still don't have anything in xml when U trie to return it, your method returns before sendAsynchronousRequest finishes.
USE:
NSData* data=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString* xml = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
It will wait until U get the result back.
You have several major problems. For starters, your block executes after your connection finishes. The code after the block executes after the connection STARTS. This means you releasing the connection before it finishes.
Additionally, you are creating NSURLConnection *theConnection, but never using it. When you call -sendAsynchronousRequest:queue:completionHandler: it creates a completely new handler.
The specific error you are getting is because you cannot return a value from the block. The fact that you are trying indicates that you do not have a full grasp of exactly what is happening. There are many good references around the Internet about blocks and asynchronous programming. I suggest you find one.
NSURL *targetURL = [NSURL URLWithString:l_uri];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:targetUrl
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
[theRequest setHTTPMethod:requestTechnique];
[theRequest setValue:#"application/xml" forHTTPHeaderField:#"Accept"];
[theRequest setValue:#"application/x-www-form-unrlencoded" forHTTPHeaderField: #"Content-Type"];
[theRequest setValue:l_api_key forHTTPHeaderField: #"EMApikey"];
[theRequest setValue:[self hmacsha1:l_uri secret:l_secret_key] forHTTPHeaderField: #"EMRequestHash"];
[NSURLConnection sendAsynchronousRequest:theRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
// Here the connection is complete and the data is usable.
NSString *xml = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self myMethod:xml];
[xml release];
}];
// Here the Connection has only been queued and no data is available.

App crashes on slow InternetConnection

I am getting data from server in applicationDidBecomeActive method.When net connection is too slow app keep crashing.I do not know how to handle this problem.any help will be appreciated.thanks in advance.
NSString *post =[[NSString alloc] initWithFormat:#"=%##=%#",myString,acMobileno];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http:///?data=%#&no=%#",myString,acMobileno]];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
NSError *error1 = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error1];
NSString *string;
if ([response statusCode] >=200 && [response statusCode] <300)
{
string = [[NSString alloc] initWithData:urlData encoding:NSMacOSRomanStringEncoding];
}
It's probably crashing because the connection has started downloading, but it hasn't finished therefore allowing the complier to pass your if statement, which would inevitably give a nil urlData parameter.
To fix this, you should be checking to see if there is an error, and then the response headers for the download. Also, I recommend running this operation on a background thread so that it doesn't block the user experience - at the moment, the app will have a delayed launch depending on the size of your file, and the user's download speed.
NSError *error1 = nil;
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error1];
NSString *string = nil;
if (error != nil && ([response statusCode] >=200 && [response statusCode] <300)){
string = [[NSString alloc] initWithData:urlData encoding:NSMacOSRomanStringEncoding];
}
else {
NSLog(#"received error: %#", error.localizedDescription);
}
For a background thread, run the above code in a dispatch_async statement, or use -sendAsynchronousRequest: instead of -sendSynchronousRequest.
Alternatively, as #Viral said, it is possible that the request is taking too long, and the app is hanging as a result of the synchronous request not finishing before the UI should have been loaded.
Most probably, it's due to synchronous call in Application's delegate method. It is taking too much time to load the UI (As internet connection is slow and you are calling the web service on main thread); and therefore OS thinks your App has hanged due to unresponsive UI and crash the App itself.
Just for debugging purpose, try the same code in your FirstViewController's viewDidAppear method. It should work fine there. And if it is so, you need to change your call to somewhere else (also, preferably in some background thread, OR Async).
EDIT: Though, If it works elsewhere, you need to change the call as Async OR on background thread for smoother UX.

RaptureXML weird behaviour

I am getting an error (well it doesn't shows, just crashes out of app, no info on console)
that seems to happen whenever i call the method Iterate from RXML's rootXML:
-(void)valueSearch {
//FIRST CONNECTION
NSString *serverAddress = #"http://www.commix.com.br/clientes/grupoglobo/apple/valor.xml";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serverAddress]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
NSError *requestError;
NSURLResponse *urlResponse = nil;
response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
//SECOND CONNECTION - Just an encapsulated form of the first, since i use it in other parts
// of the code
response = [self requestWithParameters:#"valor.xml"];
//i just uncommented both. but actually only one (connection) runs.
//Creation of the rooXML so i can grab the info i need
RXMLElement *rootXML = [RXMLElement elementFromXMLData:response];
//This array is where i'll keep the info from the files.
//it`s deallocated at the end in dealloc
searchResult = [[NSMutableArray alloc] init];
//This is the culprit. Atleast it seems so, since putting NSLog before and after
//revealed so.
[rootXML iterate:#"valor" usingBlock: ^(RXMLElement *valor) {
NSLog(#"valor: %#", [valor child:#"nome"].text);
[searchResult addObject:[valor child:#"nome"].text];
}];
}
The thing is, when i comment the requestWithParametersand use the normal non-encapsulated style (//FIRST CONNECTION) i don't get errors. But if i use the second, when the program reaches [rootXML iterate: [...]]it crashes there without warning.
using RaptureXML: https://github.com/ZaBlanc/RaptureXML
It also happens in another part of the code:
-(void)vehicleSearch {
NSString *path = [[NSBundle mainBundle] pathForResource:#"idArray" ofType:#"plist"];
NSMutableArray *idArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serverAddress]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
NSError *requestError;
NSURLResponse *urlResponse = nil;
response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
RXMLElement *rootXML = [RXMLElement elementFromXMLData:response];
searchResult = [[NSMutableArray alloc] init];
[rootXML iterate:#"modelo" usingBlock: ^(RXMLElement *modelo) {
NSLog(#"modelo: %#", [modelo child:#"nome"].text);
[searchResult addObject:[modelo child:#"nome"].text];
}];
[idArray release];
}
Happens at the same line [rootXML iterate:].
Sorry for leaks and stuff, i'm inexperienced (thats why i'm here), Thanks!
EDIT:
ACTUALLY the culprit is the line
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]);
if i pass the parameter directly, without variables, it works:
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=4");
it shows correctly.
Are you sure that ,[idArray objectAtIndex:0] is an NSString?
Try to use
[NSString stringWithFormat:#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]];`
Or even
[NSString stringWithFormat:#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[[idArray objectAtIndex:0]stringValue]];
response = [self requestWithParameters:#"valor.xml"];
if response is a property use self.response otherwise you will have memory leak issues.

Simple http request in gnustep's objective c not working

#import <Foundation/Foundation.h>
main() {
NSURL *url = [NSURL URLWithString:#"http://www.google.com/"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60];
NSURLResponse *response;
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Data were download below:\n%#", [[NSString alloc] initWithData:data encoding: NSASCIIStringEncoding]);
}
run the executable ->
Data were download below:
[null]
Why?
Have you tried allocating the request and error?
NSURLResponse *response = [[NSURLResponce alloc] init];
NSError *error = [[NSError alloc] init];