Wait for code to finish execution - objective-c

I would like to know the easiest way to wait for code to finish execution within an objective c project because I am calling a webservice and retrieving the results and instead it is retrieving the results before the webservice has finished being called and filled.
Any suggestions please?
Btw this is my webservice code:
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:tmpURl];
[theRequest addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[theRequest addValue:#"http://tempuri.org/GetCategory" forHTTPHeaderField:#"SOAPAction"];
NSString *msgLength=[NSString stringWithFormat:#"%i",[soapMessage length]];
[theRequest addValue:msgLength forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:[soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
and the code I am using to call this method from the other class:
images = [ws callWebService:api :data];
images = [ws returnArray];
now the problem is, that the second line is being executed before the first has finished

You do it easily as below,
-(void)aFunc {
Do Asynchronous A job...
while (A is not finished) {
// If A job is finished, a flag should be set. and the flag can be a exit condition of this while loop
// This executes another run loop.
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
Do things using the A's result.
}

You could use one of many of the Cocoa design patterns (Delegate, Notification, etc).
For instance you would trigger the method and wait until you receive a response back.
It looks like you are using an asynchronous request and for this case, you would need to wait until one of the delegate methods get notified that the request has finished (with error or success).
BTW, what does your request look like? Could you share some code to explain how you do the request and when and what you want to do?
Edited after the code was inserted:
You set self as the delegate of the request, and so you should be able to handle the responses.
Have a look at the NSURLConnection Class Reference. You will need to trigger your parser when the request finishes on these methos, for example:
– connection:didReceiveResponse:
– connection:didReceiveData:
– connection:didFailWithError:
Cheers,
vfn

Related

NSThread is failing to load Selector method

So, I am trying to connect to a remote server to get and show data. in viewDidLoad I use an NSThread to call a function called doSomething
- (void)doSomething
{
#autoreleasepool
{
NSMutableURLRequest *httpRequest = [NSMutableURLRequest requestWithURL:someURL];
[httpRequest setHTTPMethod:#"POST"];
[httpRequest setValue:[NSString stringWithFormat:#"%d", httpRequestParametersClean.length] forHTTPHeaderField:#"Content-Length"];
[httpRequest setValue:#"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[httpRequest setHTTPBody:httpRequestParametersClean];
(void)[[NSURLConnection alloc] initWithRequest:httpRequest delegate:self];
for (NSString* key in response)
{
// loop through returned values
}
}
}
The code in viewDidLoad is
[NSThread detachNewThreadSelector:#selector(someURL) toTarget:self withObject:nil];
Then I have a REFRESH button which when clicked calls doSomething as well
by simply saying [self doSomething]
My problem is that when view is loaded, the response from server comes empty. I still get no response until I click on the refresh button. Strange! What am I doing wrong?
A NSURLConnection created with initWithRequest:delegate: works asynchronously, calling the delegate functions connection:didReceiveResponse:, connection:didReceiveData:, ... later, when data is read from the server. Your code does not even start the connection, so nothing will happen anyway.
The easiest way to fix your problem is to use the synchronous version
sendSynchronousRequest:returningResponse:error:
of NSURLConnection. If doSomething is executed in a separate thread, this will not block the UI.
Added: (Thanks to #geowar for mentioning this.) Note that you can also use the delegate-based NSURLConnection methods. These are more flexible (see e.g. https://stackoverflow.com/a/15591636/1187415 for a comparison). Another good choice is sendAsynchronousRequest:queue:completionHandler:, which creates a background thread automatically.

ASIHTTPRequest how to recognize finished request and failed request?

In my application, i have a button wich calls an ASIHTTPRequest. The request goes fine and i receive an response string. But when the request finishes, it always goes to the method: requestFinished. And i also got a requestFailed method. But even when i give a wrong link, the request finsihes and never fails.. Why is this? This is my code:
-(void)fetchForm:(id)sender {
NSURL *URL=[NSURL URLWithString:#"http://www.mydomain.nl/testGet.php"];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:URL] autorelease];
[request setDelegate:self];
[request setDidFailSelector:#selector(requestFailed:)];
[request startAsynchronous];
}
-(void)requestFinished:(ASIHTTPRequest *)request {
NSLog(#"Request Success!");
}
-(void)requestFailed:(ASIHTTPRequest *)request {
NSLog(#"Request Failed!");
}
EDIT:
I read a little documentation on the ASIHTTPRequest website. And i came to the conclusion that i need to see for myself if there is an error code. i do this with:
int statusCode = [request responseStatusCode];
if (statusCode == 404) {
NSLog(#"Statuscode 404 has occured!");
}
There are several conditions that might affect error reporting with HTTP requests. From ASIHTTP's viewpoint, if the request object can be successfully built, sent, and a some kind of response is received, then everything is ok.
In my case, for example, my ISP has a proxy that will return an error page with many not existing URLs and sometimes even with ill-formed URLs. In such cases, ASIHTTP will not fail. I don't know if this is also your case, but it was for me.
If you look at the file ASIHTTPRequest.m and search for failWithError, you will see all the cases where ASIHTTP will trigger the mechanism that leads to the didFailSelector to be called. You might even set a breakpoint in the failWithError method to see if it is called.
EDIT:
In a sense ASIHTTPRequest mechanism is very basic and covers failures at the network level. If you receive a response then it is an application level failure and you have to deal with it.
First thing is checking the HTTP status code:
int statusCode = [request responseStatusCode];
NSString *statusMessage = [request responseStatusMessage];
This will allow you to identify 404, 500, and so on.
If this does not work and the server does not send an error code, then the only way to go about it is parsing the response you receive and, if it does not contain the data you were waiting for, fail.
try this one -
[request setDidFailSelector:#selector(requestFailed:)];
try this:-
[request setDidFinishSelector:#selector(requestFinished:)];
[request setDidFailSelector:#selector(requestFailed:)];
Write these two lines and then try.

How to detect when a NSURLConnection has finished

I'm trying to use NSURLRequest and NSURLConnection to get a small bit of data (around 50 bytes) from a web API. I'm pretty sure the code below is right, but how do I actually get the received data and detect when its all downloaded?
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:req delegate:self];
By implementing NSURLConnectionDelegate, you can get the data in connection:didReceiveData: method and the connectionDidFinishLoading: method will be called when the the operation is over. Meanwhile , connection:didFailWithError: will be called if there is some error during the operation.
you set yourself as the delegate and the connection will send you calls as it goes.
example:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
You have to use delegate's methods, read the documentation here: http://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSURLConnectionDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intf/NSURLConnectionDelegate

Simple ASIHTTPRequest-based function seems to hang at upload

I've recently started trying to implement HTTP upload support to a program, but I've been having some difficulty doing so. This is the first time I've ever used objective-c (although I have a C background), so I'm still very new to the language. I've been trying to get it to work using the HTTPRequest library, but haven't been able to get anything to start working. It's a fairly large program (2500~ lines) so I won't paste it here. I'll just paste the function itself here.
- (void)Upload2HTTP2:(NSString *)ZipPath
{
[self UpdateProgressBar:#"Upload2HTTP opening Connection to Website..."];
NSLog(#"Upload2HTTP called\n");
//URL to be used to upload
NSURL *url = [NSURL URLWithString:#"http://ftp.website.com"];
NSLog(#"Upload2HTTP -%#\n",url);
//Creates the new ASIFormDataRequest object to do the uploading
//Uses the ASIHTTPRequest and ASIFormDataRequest libraries
// http://allseeing-i.com/ASIHTTPRequest/ for more information
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request addRequestHeader:#"Referer" value:#"http://ftp.website.com"];
//Sets the authentication information
//This should have already been retrieved in RetrieveFromBrowser
[request setUsername:RespUID];
[request setPassword:RespPWD];
//Sets the file to be uploaded
[request setFile:ZipPath forKey:#"Customer Upload"];
//Starts the transfer?
[request startAsynchronous];
}
ZipPath, RespUID, and RespPWD are all set in another area of the program. Basically, I've got the username/PW for the HTTP authentication, and the path to the file I want to upload, but I've very little experience with the language and this library, so I'm a bit lost. I can't give any specific errors or reasons as to why it hangs, I just know that after I click upload in the program, it runs through this function, and the program hangs trying to upload the file. Is there anything I'm missing or doing wrong in this function? I'd really appreciate any help you guys could lend.
Thanks :)
ASIHTTPRequest's asynchronous networking takes advantage of the delegate design pattern. Setting the request's delegate property to self, having that class adhere to the ASIHTTPRequestDelegate protocol, and implementing - (void)requestDidFinish: and - (void)requestdidFail: should give you callbacks for finish and failure. Quick example:
- (void)Upload2HTTP2:(NSString *)ZipPath
{
...
request.delegate = self;
[request startAsynchronous];
}
- (void)requestDidFinish:(ASIHTTPRequest *)request
{
NSLog(#"Success! Do stuff here with [request responseData] or [request responseString]");
}
- (void)requestDidFail:(ASIHTTPRequest *)request
{
NSLog(#"Failure! Check out [request error] for details");
}

NSURLConnection synchronous problem

I am writing an iPhone app which will call a webservice method by using soap message format.
I need a synchronous process because table view needs those data before it can be displayed.
So I use [NSURLConnection sendSynchronousRequest:returningResponse:error:]
The problem is, the whole program will exit without any error message after the method call.
Even I put a NSLog statement just after the
[NSURLConnection sendSynchronousRequest:returningResponse:error:],
there is no any output so I am sure the program exit during that method call. Actually during
that HTTP request and response stuff.
However, if I set a breakpoint before that method call, and run the program in debug mode,
everything runs well, the program will not exit, and I got my results as well.
Can anyone figure out what is going on?
Thanks.
- (void) sendSyncHTTPRequest:(NSString *)request_data operation:(ServOperationSync *)serv_ops {
id<ServiceData> serv_data = serv_ops.dataDelegate;
NSURL *urlAddr = [NSURL URLWithString:[serv_data getServURL]];
urlRequest = [NSMutableURLRequest requestWithURL:urlAddr
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:90];
NSData *requestData = [request_data dataUsingEncoding:NSUTF8StringEncoding];
[urlRequest setValue:#"MobilePortal" forHTTPHeaderField:#"User-Agent"];
[urlRequest setValue:[serv_data getSoapAction] forHTTPHeaderField:#"SOAPAction"];
[urlRequest setValue:[NSString stringWithFormat:#"%u", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[urlRequest setValue:urlAddr.host forHTTPHeaderField:#"Host"];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:requestData];
NSLog(#"just before sending http request");
[serv_ops.responseData setData:[NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&urlResponse error:&urlError]];
NSLog(#"after sending http request");
}
Note that urlResponse and urlError are declared as instance variables.
You didn't provide us enough code to find out why your app doesn't behave correctly.
Using [NSURLConnection sendSynchronousRequest:returningResponse:error:] is generally a bad idea, because it blocks the current thread. You are probably calling it from the main thread, this will block the UI. The app won't respond to touches and feels like frozen, when the request takes long (especially on low bandwidth connection like EDGE).
The nature of networking is asynchronous. So I'd advise you to make an asynchronous request instead or use GCD. Update the Tableview in delegate methods (connection:didReceiveData: etc.). You may save the tableview data in an NSMutableArray and call [tableView reloadData] after modifying the array. The tableview would then be constructed from that array in the UITableViewDataSource delegate methods.
You need:
a run loop on your code
and don't forget your NSURLConnection
delegates