How to do multiple serial connection using nsurlconnection? - objective-c

i am new to iPhone development so i don't know whether this is simple or complicated.
Here is my problem. I have a app which first connects to web service for authentication process. After authentication i need to get data of logged in user. So, how to connect to web services twice and serially using NSURLConnection. Serially means first login and then retrieve data. In my case, the request are sent in random order, means sometime it sends login request first and some time retrieve data request.
Can anyone please help this out.
Thanks.

Set the delegate of your NSURLConnection to self, and implement NSURLConnectionDelegate methods, there's a method named
- (void) connectionDidFinishLoading:(NSURLConnection*)connection
which tells you when the request was finished successfully so inside it you can call the second request.
Now your only problem is that you don't know which request to call second :) as you don't know which one was called first so what I usually do is simply, define some variable, simply an int or NSString as a tag, e.g.
Add these before your #implemenetation
#define TAG_LOGIN_REQUEST 1
#define TAG_DATA_REQUEST 2
now define this inside the class
int currentTag
now before you start the login request add this
currentTag = TAG_LOGIN_REQUEST;
and before you start the data request add this
currentTag = TAG_DATA_REQUEST;
whenever this delegate method gets called
- (void) connectionDidFinishLoading:(NSURLConnection*)connection
you simply check
if (tag == TAG_LOGIN_REQUEST) {
// send data request
}
else if (tag == TAG_DATA_REQUEST) {
// send login request
}
I hope this helps, if there's anything that's not clear, please tell me.

Just try to synchronise you calling. Here is a example:
request for login and wait for login response
get login response and call getData()
if login response if yes, request for data.
Hope this helps.. :)
EDIT:
maintain two global flag (variable). let loginReq and dataReq are those flag.
before calling getLogin(), make loginReq = true;
in your connectinDidFinishLoading check
if(loginReq == true){
loginReq = false;
dataReq = true;
getData();
}
else if(dataReq == true){
dataReq = false;
}

Related

Winsock UDP sendto and get respond back like function?

I am try to figure out if the Winsock UDP way of sending and recieving datagrams has an option to get a respond back to the sendto() like a function.
To make it clear lets say that i have a function that uses UDP to send a message
and needs to return back a true or false state
Since this function is using UDP to send a message, the application that recieves the message needs to execute a specific command and send back the returned value of true false to the UDP sender, so in that way the function from the control program will know that the function was properly executed or not.
Application 1 :
bool Test(){
functionToRun = "checkandRespond";
respond = sendto(....);
if(respond == "true"){
Brespond = true;
}else{
Brespond = false;
}
return Brespond;
}
Application 2 :
bool check(){
return true;
}
DWORD WINAPI IncomingMessages(){
recvfrom(....)
//run the function requested e.x.
bool respondto1App = check();
sendback the respondto1App boolean to string to Application 1
}
Is there any way to get back an instant respond like a function needs between two applications using UDP ?
NOTE : i don`t want to know if the sendto() command has send the message to the other application successfully, i want to get the respond back from the second application like if i was running the check() function from application 1.
Thanks in advance for any help on the issue

ReactiveCocoa binding "networkActivityIndicator" Crushes

I have this code:
RAC(self.viewModel , password) = self.signupCell.passwordTextField.rac_textSignal;
RAC(self.viewModel , userName) = self.signupCell.usernameTextField.rac_textSignal;
RAC([UIApplication sharedApplication], networkActivityIndicatorVisible) = self.viewModel.executeRegister.executing;
At my LogIn page.
At first is runs perfect, But it user Logout and gets to the register page once again, the app crushes at the line:
RAC([UIApplication sharedApplication], networkActivityIndicatorVisible) = self.viewModel.executeRegister.executing;
With Error:
'Signal name: is already bound to key path "networkActivityIndicatorVisible" on object , adding signal name: is undefined behavior'
I'm guessing it has something to do with subscribing to UIApplication events. But I'm not sure what else can i do beside sending subscriber completed as so:
[subscriber sendCompleted]
Any one had the same problem?
thanks.
EDIT
With the help of #erikprice and #powerj1984 I found a solution:
RAC([UIApplication sharedApplication], networkActivityIndicatorVisible) = [self.viewModel.executeRegister.executing takeUntilBlock:^BOOL(id x) {
return _viewShowing;
}];
The "_viewShowing" veritable is setted to YES on ViewWillAppear, And to NO on ViewWillDisapear.
This is not the best coding.. So if anyone has a better option i would be happy to use it.
Thanks.
That error message means that you're trying to call RAC(UIApplication.sharedApplication, networkActivityIndicatorVisible) more than once. Make sure you only make that call on that specific property of that specific object one time, ever. (Or at least until such time as you dispose of the subscription, as #powerj1984 suggests.)

WCF Async deadlock?

Has anyone run into a situation where a WaitAny call returns a valid handle index, but the Proxy.End call blocks? Or has any recommendations or how best to debug this - tried tracing, performance counters (to check the max percentages), logging everywhere
The test scenario: 2 async. requests are going out (there's a bit more to the full implementation), and the 1st Proxy.End call return successfully, but the subsequent blocks. I've check the WCF trace and don't see anything particularly interesting. NOTE that it is self querying an endpoint that exists in the same process as well as a remote machine (=2 async requests)
As far as I can see the call is going through on the service implementation side for both queries, but it just blocks on the subsequent end call. It seems to work with just a single call though, regardless of whether it is sending the request to a remote machine or to itself; so it something to do with the multiple queries or some other factor causing the lockup.
I've tried different "concurrencymode"s and "instancecontextmode"s but it doesn't seem to have any bearing on the result.
Here's a cut down version of the internal code for parsing the handle list:
ValidationResults IValidationService.EndValidate()
{
var results = new ValidationResults();
if (_asyncResults.RemainingWaitHandles == null)
{
results.ReturnCode = AsyncResultEnum.NoMoreRequests;
return results;
}
var waitArray = _asyncResults.RemainingWaitHandles.ToArray();
if (waitArray.GetLength(0) > 0)
{
int handleIndex = WaitHandle.WaitAny(waitArray, _defaultTimeOut);
if (handleIndex == WaitHandle.WaitTimeout)
{
// Timeout on signal for all handles occurred
// Close proxies and return...
}
var asyncResult = _asyncResults.Results[handleIndex];
results.Results = asyncResult.Proxy.EndServerValidateGroups(asyncResult.AsyncResult);
asyncResult.Proxy.Close();
_asyncResults.Results.RemoveAt(handleIndex);
_asyncResults.RemainingWaitHandles.RemoveAt(handleIndex);
results.ReturnCode = AsyncResultEnum.Success;
return results;
}
results.ReturnCode = AsyncResultEnum.NoMoreRequests;
return results;
}
and the code that calls this:
validateResult = validationService.EndValidateSuppression();
while (validateResult.ReturnCode == AsyncResultEnum.Success)
{
// Update progress step
//duplexContextChannel.ValidateGroupCallback(progressInfo);
validateResult = validationService.EndValidateSuppression();
}
I've commented out the callbacks on the initiating node (FYI it's actually an 3-tier setup, but the problem is isolated to this 2nd tier calling the 3rd tier - the callbacks go from the 2nd tier to the 1st tier which have been removed in this test). Thoughts?
Sticking to the solution I left in my comment. Simply avoid chaining a callback to an aysnc calls that have different destinations (i.e. proxies)

How is it better to wait an asynchronous method to be finished in iPhone app?

everybody.
I want to understand, how i shoud procceed situations when an asynchronous method has "didFinish:#selector(SEL)" parameter.
My code example is:
//
// Authentication check
- ( void )authenticationSuccess: ( GDataServiceTicket* ) ticket
authenticatedWithError: ( NSError* ) error {
if ( error == nil )
{
NSLog( #"authentication success" );
}
else
{
NSLog( #"authentication error" );
}
}
//
- ( void ) fetchFeedOfSpreadsheets {
//create and authenticate to a google spreadsheet service
if ( !(mService) )
{
GDataServiceGoogleSpreadsheet *service = [self spreadsheetService];
[mService autorelease];
mService = [service retain];
}
// check autentication success ( invoke "authenticationSuccess" method for debug success & error )
[mService authenticateWithDelegate: self
didAuthenticateSelector:#selector(authenticationSuccess:
authenticatedWithError:) ];
// HERE I WANT TO MAKE A PAUSE AND WHAIT THE RESULT, EITHER I AUTHENTICATED OR NOT
// AND MAKE AN "IF" STATEMENT TO CONTINTUE WORKING ON SERVER, OR RETURN ERROR
//fetch retrieves the feed of spreadsheets entries
NSURL *feedURL = [ NSURL URLWithString: kGDataGoogleSpreadsheetsPrivateFullFeed ];
GDataServiceTicket *ticket;
ticket = [mService fetchFeedWithURL: feedURL
delegate: self
didFinishSelector: #selector(spreadsheetsTicket:finishedWithFeed:
error: ) ];
// HERE I WANT TO WAIT SECOND TIME. I WANT "spreadsheetsTicket:
// finishedWithFeed:error:" TO PROCCEED ERROR AND PUT A FEED IN SOME NSARRAY OBJECT
// AND AFTER THAT I WANT TO WORK WITH THAT NSARRAY RIGHT HERE
}
I's clear, that i can push the code i want into the end of "authenticationSuccess" method section, but it's also clear, that it's a wrong a way to solve the proble. There a number of situations like this, where i call an asynchronous method with a selector parameter, and i want to find a solution providing me a flexible code writing.
Thanks in advance.
It's a standard practice in Objective-C to put the code to be executed after the authentication in the authenticationSucess: method. You might not like it, but that is life.
Many people had the same complaint as you, so
on iOS 4 and later, there's something called blocks which allow you to write the code to be executed after the authentication in the method which initiates the authentication, as in
[mService authenticateAndExecute:^{
code to be executed when successfully authenticated ;
} whenError:^{
code to be executed when authentication failed;
} ];
But in this case you need to modify the API, which is possible by using categories. See this blog post by Mike Ash. He has many other posts on blocks on the same blog, which are also very instructive.
If you're going to use a library that works asynchronously (and therefore doesn't block your UI), you should have a good reason for trying to force it to work synchronously.
You should be checking for an authentication error at the end of your authenticationSuccess:authenticatedWithError: method, and calling the next request from there if there's a success. Similarly, in your spreadsheetsTicket:finishedWithFeed:error: check for an error, and continuing processing if there isn't one. It might be a better design to do that continued work in a separate method, but that's up to you.
Is there a specific reason you want to use the GData API in a synchronous fashion?

Persisted properties - asynchronously

In classic ASP.NET I’d persist data extracted from a web service in base class property as follows:
private string m_stringData;
public string _stringData
{ get {
if (m_stringData==null)
{
//fetch data from my web service
m_stringData = ws.FetchData()
}
return m_stringData;
}
}
This way I could simply make reference to _stringData and know that I’d always get the data I was after (maybe sometimes I’d use Session state as a store instead of a private member variable).
In Silverlight with a WCF I might choose to use Isolated Storage as my persistance mechanism, but the service call can't be done like this, because a WCF service has to be called asynchronously.
How can I both invoke the service call and retrieve the response in one method?
Thanks,
Mark
In your method, invoke the service call asynchronously and register a callback that sets a flag. After you have invoked the method, enter a busy/wait loop checking the flag periodically until the flag is set indicating that the data has been returned. The callback should set the backing field for your method and you should be able to return it as soon as you detect the flag has been set indicating success. You'll also need to be concerned about failure. If it's possible to get multiple calls to your method from different threads, you'll also need to use some locking to make your code thread-safe.
EDIT
Actually, the busy/wait loop is probably not the way to go if the web service supports BeginGetData/EndGetData semantics. I had a look at some of my code where I do something similar and I use WaitOne to simply wait on the async result and then retrieve it. If your web service doesn't support this then throw a Thread.Sleep -- say for 50-100ms -- in your wait loop to give time for other processes to execute.
Example from my code:
IAsyncResult asyncResult = null;
try
{
asyncResult = _webService.BeginGetData( searchCriteria, null, null );
if (asyncResult.AsyncWaitHandle.WaitOne( _timeOut, false ))
{
result = _webService.EndGetData( asyncResult );
}
}
catch (WebException e)
{
...log the error, clean up...
}
Thanks for your help tvanfosson. I followed your code and have also found a pseudo similar solution that meets my needs exactly using a lambda expression:
private string m_stringData;
public string _stringData{
get
{
//if we don't have a list of departments, fetch from WCF
if (m_stringData == null)
{
StringServiceClient client = new StringServiceClient();
client.GetStringCompleted +=
(sender, e) =>
{
m_stringData = e.Result;
};
client.GetStringAsync();
}
return m_stringData;
}
}
EDIT
Oops... actually this doesn't work either :-(
I ended up making the calls Asynchronously and altering my programming logic to use MVVM pattern and more binding.