How to handle chunking while streaming JSON data to NSURLConnection - ios

I have a web server that is streaming JSON results back asynchronously to an iOS client. The client is connecting using NSURLConnection and I access the data from the method:
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData)
Data is currently coming back in 1024 byte chunks. However, I'm not sure how to tell if when I receive data if the message was complete other than appending all the data I receive to a string and try to parse it to JSON each time. This method seems quite error prone - is there a better way to handle this? Something that would mark in the headers or something when a full response has been sent?

You have two ways
first & better way is implement connectionDidFinishLoading: NSURLConnectionDataDelegate delegate which will trigger when a connection has finished loading successfully.
Second way is handling it manually as follows.
You can do the following things in Web-server side,
Step1: Send the below informations first before starting to send the original data.
a.Number of Chunks.[totalSize/1024] (mandatory).
b.TotalSize(not mandatory).
You can do the following things in Client side side,
Step1: Store the above informations.
Step2: Write the below code
#property (nonatomic,assign) int chunkNumber;
#property (nonatomic,strong) NSData *receivedData;
Self.chunkNumber = 1;
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData)myata{
if(self.chunkNumber != Number of Chunks)
{
if(!self.receivedData)
{
//allocate and initialize self.receivedData
}
[self.receivedData appendData:myData];
}
else
{
//completed . do whatever with self.receivedData.
//if you want to validate, just check the self.receivedData size with TotalSize
self.chunkNumber = 1;
}
}

In the NSURLConnectionDataDelegate, there is a method connectionDidFinishLoading: that should be called when the server is done sending. You can also retrieve the expected length in didReceiveResponse but that is not reliable and required server side support.

Related

How to call xml-rpc webservice using objective c

Suppose, the webservice provider's server exposing the webservice in the form http://example.com:8000/api
What is best framework or library to access the webservice in ios 7 project
There are a few marshaling frameworks that support generating an object-graph from XML, however I would simply go for the following:
Invoke the service endpoint. My favorite library is BBHTTP, however you could use AFNetworking, NSURLConnection with gcd or whatever you prefer for asynch network calls.
Extract the relevant contents of the XML payload onto your use-case specific payload object using RaptureXML
I recommend having use-case specific payload objects because they model exactly what is needed for a given service invocation - supporting the notion of contract-first development. This allows you to change you internal model without effecting the integration to external systems. Similarly the external API can change without effecting your model.
You can create a category method on RXMLElement to return the element mapped to a use-case-specific object. A typical mapping usually takes just a handful of lines of code to marshal from wire-format to your payload object for the service invocation.
Here's an example (the code that I took it from wanted the payload wrapped in a SOAP envelope - just ignore that bit).
- (void)request:(MyUseCaseRequstPayload*)request onComplete:(void (^)(MyResponsePayload*))onSuccess
onError:(void (^)(NSError*))onError;
{
//Even more XML! You can stick your payload inside an envelope if you want
SoapEnvelope* envelope = [SoapEnvelope envelopeWithContent:[request xmlString]];
[[BBHTTPRequest postToURL:_serviceUrl data:[envelope data] contentType:#"text/xml"] execute:^(BBHTTPResponse* response)
{
RXMLElement* element = [RXMLElement elementFromXMLData:[response content]];
MyResponsePayload* response = [[element child:#"elementToBeMapped"] asMyObjectType];
if (onSuccess)
{
onSuccess(response);
}
} error:^(NSError* error)
{
LogDebug(#"Got error: %#", error);
if (onError)
{
onError(error);
}
}];
}

Upload file via Soap message using MTOM in iOS

I have found here Upload file via Soap message in detail. But i have another issue if there is large file in Soap then it creates memory issues cause of file loads in memory for sending via Soap message.
I read about MTOM (Message Transmission Optimisation Mechanism). "When you use MTOM/XOP to optimise a SOAP message, the XOP processing serialises it into a MIME Multipart/Related message. The XOP processing extracts the base64Binary data from the SOAP message and packages it as separate binary attachments within the MIME message, in a similar manner to e-mail attachments"
I have found how to use this approach in java here Soap with Attachments and MTOM in Java
Now i have two questions :-
By using MTOM/XOP approach in iOS we can reduce Or solve the
issue of memory as explaind above.
In programming How we can use MTOM/XOP approach in iOS.
Any help will be appriciated.Thanks in advance.
I have done same request using the Rest Kit.Rest kit allows to send attachment in MTOM Specification.
First thing you need is to download Restkit.
Following is the code snippet for the MTOM using the RestKit.
abv.h
#import "RestKit/RestKit.h"
RKObjectManager *man;
RKObjectLoader *loader;
abc.m
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
//Start Progress bar
RKParams * params = [[RKParams alloc] init];
UIImage *image=[UIImage imageNamed:#"zbar-samples.png"];
RKObjectManager *man;
NSData * fileData=UIImageJPEGRepresentation(image,0.7);
[params setValue:#"1234" forParam:#"encryptedToken"];
[params setValue:modelObj.docNameTobeSent
forParam:#"documentName"];
RKParamsAttachment * attachments = [params setData:fileData forParam:#"file"];
[attachments setMIMEType:#"image/jpeg"];
[attachments setFileName:[NSString stringWithFormat:#"%#.jpeg",modelObj.name]];
self.man = [RKObjectManager objectManagerWithBaseURL:YOUR URL];
self.loader = [self.man loadObjectsAtResourcePathUsingPOSTRPC:#"upload.form" objectMapping:nil PostParams:params delegate:self];
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error
{
//Handle fail error
//stop Progress bar
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects
{
NSLog(#"%#",#"didLoadObjects");
}
- (void)objectLoaderDidFinishLoading:(RKObjectLoader*)objectLoader
{
NSLog(#"%#",#"objectLoaderDidFinishLoading");
//stop Progress bar
}
- (void)objectLoaderDidLoadUnexpectedResponse:(RKObjectLoader*)objectLoader
{
NSLog(#"%#",#"objectLoaderDidLoadUnexpectedResponse");
//stop Progress bar
}

How get the status of a server without download the page content in IOS

I want to check if a web ressource is available without download any data. For exemple, if I do a NSURLConnection on a webPage, I can get the status code:
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int code = [httpResponse statusCode];//200 is ok
}
But all page datas are downloaded.
How can I get this code (or equivalent) without download this page ?
The status code comes along with the server answer, once you get the status code you will have the body as well.
Another option is maybe to check if the resource is reachable using the Reachability classes.
Check this example, it may help.
Update: borrrden pointed in the right direction here (use HEAD method instead of GET) check the comment on your anwser

How to check status of web server in iOS?

I need to check status of web server, specifically, the information if the web server returns proper status code 200. Is there any way to get the HTTP response code from web server in iOS?
This is well documented in the official docs, with no need to implement a 3rd party library (although if you're new to iOS coding, a Networking API can simplify the underlying function calls). Your class must be an NSURLConnection delegate, and after making the NSURLConnection you implement the delegate method something like this:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse*)response
{
if ([response statusCode] == 200) {
// Handle valid response (You can probably just let the connection continue)
}
else {
// Other status code logic here (perhaps cancel the NSURLConnection and show error)
}
}
You should find the URL Loading Guide very useful reading for this and other networking functions on iOS.

How to make webservice pass errors through NSURLConnection's connection:didFailWithError:?

What does a web service need to do to cause NSURLConnection's delegate to receive the connection:didFailWithError: message?
For example:
iOS app passes a token to the web service, web service looks up the token, and then the web service needs to respond with an error saying "invalid token" or something of the like.
Currently, the data is received, and in "connectionDidFinishLoading:" is parsed for error messages. This means I'm error checking in two places, which I am trying to avoid.
I have both the iOS app and web service completely under my control.
In my experience (the three most dangerous words in programming), -connection:didFailWithError: is only called if the HTTP exchange failed. This is usually a network error or maybe an authentication error (I don't use authentication). If the HTTP message succeeds, no matter the response code, -connectionDidFinishLoading: is called.
My solution: call -connection:didFailWithError: when I detected an error. That way all my error handling code is in one place.
At the top of my -connectionDidFinishLoading:, I have:
NSError *error;
NSDictionary *result = [self parseResultWithData:self.connectionData error:&error];
if (!result) {
[self connection:connection didFailWithError:error];
return;
}
There are many conditions on which the delegate connection:didFailWithError: of NSUrlConnection may invoke.Here's a list of those errors or constants.I think an alertview would be better to show http errors in connection:didFailWithError:.
-(void) connection:(NSURLConnection *)connection didFailWithError: (NSError *)error
{
UIAlertView *errorAlert= [[UIAlertView alloc] initWithTitle: [error localizedDescription] message: [error localizedFailureReason] delegate:nil cancelButtonTitle:#"Done" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
NSLog (#"Connection Failed");
}
While not directly related to your question, I would encourage you to move to a more high level library. I can heartily recommend AFNetworking, it is production ready and I have used it in many projects. This will allow you to inspect the response code of each request in the failure block. This project also abstracts away a lot of the low level handling that you would otherwise be required to write for network communication; I'm speaking here about parsing and creating XML / JSON strings to communicate with a service.
To give you a more focused answer to your question, I would call the cancel method of your NSURLConnection once you have noticed an error in connectionDidFinishLoading:. This will automatically cancel the request and call the failure method of the delegate object.
The documentation for NSURLConnection is pretty dry, and the failure method of the delegate does not specifically document the failure cases. You may be able to find more information in the URL Loading System Programming Guide.
I couldn't see the forrest for the trees.
I needed to step back from connection:didFailWithError: and look at a different delegate method connection:didReceiveResponse:!!
With the web service fully under my control, the endpoint could respond with a 500 status code, which gets picked up in connection:didReceiveResponse, and pass along some JSON further explaining the situation, which gets picked up and processed in connection:didReceiveData:.
The NSURLConnection delegate hangs onto a couple more bits of state throughout the process, but it has the best code smell I've found so far.
Jeffery's answer was by far most correct: the connection:didFailWithError: callback is only in relation to the network failing, any response from the web service means the connection didn't fail!

Resources