2

I have a code design question, I'm having trouble thinking of the most efficient manner to handle this:

Basically, I want to send a JSON request and read the response back from the server in one go.

I have a methods such as:

-(BOOL)sendString:(NSString *)sendString;
//This should return a NSString and a BOOL
-(NSDictionary *)loginRequestWithEmail:(NSString *)userEmail andPassword:(NSString     *)userPassword;
//This should return a NSString and a BOOL
-(NSDictionary *)requestNewUserAccountWithDisplayName:(NSString *)displayName Email:    (NSString *)userEmail andPassword:(NSString *)userPassword;

I'll explain what

-(BOOL)sendString:(NSString *)sendString;

does, Basically sends a JSON string to the server and gets a response of wether it failed or not.

I know how to write this to the server and read this. The issue is with doing this together, so I can return that BOOL value as a true or false to see if it worked.

Now after writing to a socket, I get a response and must read it through a delegate method:

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {

Which is called as soon as the server gives a response. The issue is, all this reading/writing to the socket happens asynchronously.

Since that happens, I can't have a method that does this:

-(BOOL)sendString:(NSString *)sendString{

NSError *error;

NSLog(@"Sending String: %@",sendString);

NSDictionary *blobData = [NSDictionary dictionaryWithObjectsAndKeys:
                          sendString,@"string",
                          nil];
NSString *blobString = [[NSString alloc]
                        initWithData:[NSJSONSerialization dataWithJSONObject:blobData options:kNilOptions error:&error]
                        encoding:NSUTF8StringEncoding];
NSLog(@"Blob Created: %@", blobString);
NSDictionary *requestData = [NSDictionary dictionaryWithObjectsAndKeys:
                             @"send_string",@"request_type",
                             [NSNumber numberWithInt:0],@"security_level",
                             @"ios",@"device_type",
                             //No Email Provided, This is just for testing
                             blobString,@"blob",
                             nil];

NSData *JSONRequestData = NULL;
JSONRequestData = [NSJSONSerialization dataWithJSONObject:requestData options:kNilOptions error:&error];
        NSLog(@"Contents of JSONRequestData: %@",[[NSString alloc] initWithData:JSONRequestData encoding:NSUTF8StringEncoding]);
JSONRequestData = [[[[NSString alloc] initWithData:JSONRequestData encoding:NSUTF8StringEncoding] stringByAppendingString:@"\\n"] dataUsingEncoding:NSUTF8StringEncoding];
//Write the data
NSMutableData *JSONRequestDataWithLineEnding = [[NSMutableData alloc] initWithData:JSONRequestData];
[JSONRequestDataWithLineEnding appendData:[GCDAsyncSocket CRLFData]];
[asyncSocket writeData:JSONRequestDataWithLineEnding withTimeout:-1 tag:1];

//read a response
[asyncSocket readDataWithTimeout:-1 tag:2];

//This should be done in the didRead delegate
NSString *failure = [serverJSONResponseParsed objectForKey:@"failure"];
NSLog(@"Contents of string failure: %@", failure);

if ([failure isEqualToString:@"none"]) {
    NSLog(@"Success Sending String");
    return TRUE;
}
else {
    NSLog(@"Failure: %@",failure);
    return FALSE;
}

}

Since the code that is called after

[asyncSocket readDataWithTimeout:-1 tag:2];

executes before the data is read (because it's all async).

I realize I must do something in that delegate method. Which is fine, but I have different types of responses coming in, and each response must be handled differently.

My idea is: tag each of the write commands, and then use some

if(this_tag) {do this} ....else if(that_tag) {do this} ....

in the didReadData delegate method.

But how do I return this data correctly? Sometimes I need to return a BOOL, other times I need to return an NSDictionary, NSString, etc...

I would love to be able to have each of my request methods mentioned above return their associated data, but I can't (at least not efficiently). Do I have to make two different methods for each request?

i.e.

sendString
getSendStringResponse

I'm a little confused as to how to handle this.

I apologize if I'm not being clear,

I appreciate any help that I can get.

khaliq
  • 3,125
  • 4
  • 17
  • 23

1 Answers1

1

What I would do is to create some type of protocols for this particular app. For example, let's say you have the following data types (not related to Obj-C) dat1, dat2, dat3, etc that this app needs to send and get the appropriate response back as res1, res2, res3, etc. You would come up with a signature for each data type for the sending part as well as for the responding part. Before sending each data, you need to prefix the data with the signature. On the receiver end using readDataWithTimeout, in the didReadData callback method, extract the header for the received data and the decide the response based on the protocols that you have agreed/designed earlier. There are other additional steps before this is complete design. For example, as part of your header info it might contain other info such as length of data, etc. Hope this will help you get started.

user523234
  • 14,323
  • 10
  • 62
  • 102
  • Thanks, that was the idea. I can use tags in the delegate method to determine which response is which...that way I don't have to mess with the header. – khaliq Aug 20 '12 at 07:49
  • If you use tag to determine which read statement to use then it would not work. It is because tag is never sent along with your data to the receiver. Another word, your receiver end's tag value is not the same meaning as the sender's. Unless of course you sent it as a header. – user523234 Aug 20 '12 at 11:04
  • Oh ok, I see what you mean. If the server isn't designed to handle headers, then I can't really use this option right? – khaliq Aug 20 '12 at 18:50
  • Ignore the last sentence of my last comment. It might have got you confused. Basically, there is no relationship between tag value on the sender and the receiver end. Remember: GCDAsyncSocket is a relatively low level socket communication. You will need to come up with certain application's level communication protocols yourself. – user523234 Aug 22 '12 at 02:58
  • Yes I understand. That's what I was thinking. I appreciate your help! – khaliq Aug 22 '12 at 06:02