How to download file to iphone coming as byte array? - ios

below code i use an asmx webservice to get a file as byte array and want to save it to iphone application's documents directory
the file i request is a sqlite file
and my code is :
-(void)getfile{
NSString* soapMessage = [NSString stringWithFormat:
#"<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> <soap:Body> <GetDocument xmlns=\"http://tempuri.org\"> <DocumentName>%#</DocumentName> </GetDocument></soap:Body> </soap:Envelope>", #"ErtugrulGuler"];
NSURL* theUrl = [NSURL URLWithString:#"http://test.xxxx.com/xxxxx/xxxx.asmx"];
NSString* msgLength = [NSString stringWithFormat:#"%d", [soapMessage length]];
NSMutableURLRequest* theRequest = [NSMutableURLRequest requestWithURL:theUrl];
[theRequest addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[theRequest addValue:#"http://tempuri.org/GetDocument" forHTTPHeaderField:#"SOAPAction"];
[theRequest setHTTPMethod:#"POST"];
[theRequest addValue:msgLength forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connect = [[NSURLConnection alloc] initWithRequest: theRequest delegate:self];
if (connect)
{
}
else {
NSLog(#"No Connection established");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
downloadData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
[downloadData appendData:data];
NSString *receivedDataString = [[NSString alloc] initWithData:downloadData encoding:NSUTF8StringEncoding];
NSLog(#"data string: %#",receivedDataString);
NSLog(#"data length: %d",[data length]);
//NSLog(#"bytesWritten == %d error == %#",bytesWritten,[fileOutputStream streamError]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
//NSLog(#"finish loading");
[self performSelector:#selector(downloadData:) withObject:downloadData afterDelay:0];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
}
-(void)downloadData:(NSData*)response
{
//NSLog(#" \n\n STRING = %# \n\n ",[[NSString alloc]initWithData:response encoding:NSUTF8StringEncoding]);
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir=[paths objectAtIndex:0];
NSString *documentFile=[documentDir stringByAppendingPathComponent:#"abc.sqlite"];
NSString * yourAppendingText=[[NSString alloc]initWithData:response encoding:NSUTF8StringEncoding];
[yourAppendingText writeToFile:documentFile atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
and this is my webservice method that returns byte array
[WebMethod]
public Byte[] GetDocument(string DocumentName)
{
string strdocPath;
strdocPath = "path" + DocumentName;
FileStream objfilestream = new FileStream(strdocPath,FileMode.Open,FileAccess.Read);
int len = (int)objfilestream.Length;
Byte[] documentcontents = new Byte[len];
objfilestream.Read(documentcontents,0,len);
objfilestream.Close();
return documentcontents;
}
this code connects successfully but i dont know how to get file with NSData and write the file to Documents Directory as .sqlite
#EDIT:
i solve something but the file i wanted to get is 53kb and my recieved data as string like :
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetDocumentResponse xmlns="http://tempuri.org/" /></soap:Body></soap:Envelope>
and data length : 297 so it cannot get the data i think
in asp.net i run the service and get data successfully. so there is no problem with service but maybe maxiimumrecieving size for ios could be increased? but how?

NSOutputStream *fileOutputStream;
NSString *databasePath = [NSString stringWithFormat:#"%#/Documents/%#",NSHomeDirectory(),#"database.sqlite"];
fileOutputStream = nil;
fileOutputStream = [[NSOutputStream alloc] initToFileAtPath:databasePath append:NO];
[fileOutputStream open];
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
int bytesWritten = [fileOutputStream write:[data bytes] maxLength:[data length]];
NSLog(#" %s bytesWritten == %d error == %#",__FUNCTION__,bytesWritten,[fileOutputStream streamError]);
}

Related

JSON parse error in iOS

I am trying to parse json response(which I get from result tag of a SOAP webservice response) as shown in pictures with following lines.
NSString *soapMessage = [NSString stringWithFormat:#"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
"<soap:Body>"
"<GetPhotoSession xmlns=\"http://tempuri.org/\">"
"<UserID>%#</UserID>"
"<photoSessionID>%#</photoSessionID>"
"</GetPhotoSession>"
"</soap:Body>"
"</soap:Envelope>",[HelperClass retrieveStringForKey:kUserID],self.currentSession.sessionID];
NSURL *url = [NSURL URLWithString:kBaseURL];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSString *msgLength = [NSString stringWithFormat:#"%lu", (unsigned long)[soapMessage length]];
[theRequest addValue: #"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[theRequest addValue: #"http://tempuri.org/GetPhotoSession" forHTTPHeaderField:#"SOAPAction"];
[theRequest addValue: msgLength forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if( theConnection ) {
self.webResponseData = [NSMutableData data];
}else {
NSLog(#"Some error occurred in Connection");
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.webResponseData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.webResponseData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Some error in your Connection. Please try again.");
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Received Bytes from server: %d", [self.webResponseData length]);
NSString *myXMLResponse = [[NSString alloc] initWithBytes: [self.webResponseData bytes] length:[self.webResponseData length] encoding:NSUTF8StringEncoding];
NSLog(#"%#",myXMLResponse);
NSError *errorPointer;
NSDictionary *dict = [XMLReader dictionaryForXMLString:myXMLResponse error:&errorPointer];
NSString *jsonData = dict[#"soap:Envelope"][#"soap:Body"][#"GetPhotoSessionResponse"][#"GetPhotoSessionResult"][#"text"];
NSData *data = [jsonData dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&errorPointer];
NSLog(#"%#",[json objectForKey:#"Head"]);
}
But I am getting nil in "json" object. Here is the pastie link for JSON response http://pastie.org/9799331. Following is the description of error pointer.
Printing description of errorPointer:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x7d0156a0 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
Is this your own web service or an existing one? If this is your own, are you sure your JSON is actually correct?
I believe the problem is here:
"ImageBase64Data": "/9j/4AAQSkZJRgABAQA .... blah blah ==
"
Note the key point here. That the closing double quote is on the next line. It should be
"ImageBase64Data": "/9j/4AAQSkZJRgABAQA .... blah blah =="
For future reference, it is far easier if you cut and paste the JSON payload text in your question versus showing an image.
So grabbing your data from here:
http://pastie.org/9799331#2,22,482
I have run it through this code:
NSError *error = nil;
NSString *path = [[NSBundle mainBundle] pathForResource:#"badjson" ofType:#"txt"];
NSString *jsonStr = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
// jsonStr = [[jsonStr componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:#""];
NSData *jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
NSLog(#"Error is %#", error);
NSLog(#"JSON is %#", json);
Note that I have one commented out line right now. When I do this, it fails. However the failure is different than what you listed above. I get.
Error is Error Domain=NSCocoaErrorDomain Code=3840 "The operation
couldn’t be completed. (Cocoa error 3840.)" (Unescaped control
character around character 120.) UserInfo=0x7f9519f71510
{NSDebugDescription=Unescaped control character around character 120.}
If I uncomment out that line, then it works. Only showing a snippet of the output:
2014-12-26 12:03:35.020 Sample[49732:6379864] Error is (null)
2014-12-26 12:03:35.022 Sample[49732:6379864] JSON is {
Head = (
{
ID = 1092;
ImageBase64Data = "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDACAWGBwYFCAcGhwkIiAmMFA0MCwsMGJGSjpQdGZ6eHJmcG6AkLicgIiuim5woNqirr7EztDOfJri8uDI8LjKzsb/
Your data is using an base64 output which uses newlines to delimit each encoded line. This is why you see at the end the text that looks like:
==
","ImageName"
You'll also notice the vast majority of lines in the Base64 look uniform .. because of this delimiting.
Strip out the newlines using this (you need to modify it for you code)
jsonStr = [[jsonStr componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:#""];
If that doesn't work, then you need to provide some more info:
-Is the output taken from Xcode console?
-Add in your code where the NSLog exists to get the output (if you don't have it, then please add one).
-Once you add the NSLog, provide that output
While it may seem like you've "already provided that info", there is obviously a gap in information. Else I would expect to see the same NSError output. So we're either missing steps, or maybe there is some other variance. For example, I'm running this in an iOS 8 simulator. Not that it should matter too much, but there is always a possibility that you're running on an older version of iOS that parses the JSON differently.

IOS HTTP Post Creating and handling response

I'm trying to refactor some code I had used in Phonegap Javascript that was uploading an Audio File to IOS Objective C and I'm a bit lost.
The code in JavaScript is as follows:
function uploadToClypit(file){
console.log(file);
var options = new FileUploadOptions();
options.name = file.fullPath.substr(file.fullPath.lastIndexOf('/')+ 1);
options.audioFile = file.nativeURL;
options.fileName = file.nativeURL;
options.mimeType = "audio/wav";
options.headers = {
Connection: "close"
}
options.chunkedMode = false;
console.log(options);
var ft = new FileTransfer();
console.log(file.nativeURL);
ft.upload(file.nativeURL, encodeURI("http://upload.clyp.it/upload"), win, failUpload, options);
}
And the response is handled like this:
var win = function(r){
var jsontext = r.response;
var json = JSON.parse(jsontext);
console.log(json);
}
So in IOS I am trying to create a HTTP Post Request, append an Audio File to the HTTP Body, send in some other text parameters and then handle the response.
I've done this so far.
Set my controller to implement the
Set up a NSMutableData variable *_responseData to hold the response
I create the HTTP request by doing the following:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://upload.clyp.it/upload"]]];
[request setHTTPMethod:#"POST"];
NSString *stringBoundary = #"0xKhTmLbOuNdArY---This_Is_ThE_BoUnDaRyy---pqo";
NSString *headerBoundary = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",stringBoundary];
[request addValue:headerBoundary forHTTPHeaderField:#"Content-Type"];
NSMutableData *postBody = [NSMutableData data];
[postBody appendData:[[NSString stringWithFormat:#"--%#\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"file upload\"; filename=\"uploadaudio.mp3\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[#"Content-Type: audio/m4a\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:cell];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:cellIndexPath];
ICIRecordingCell *c = (ICIRecordingCell *)cell;
NSString *fileName = c.title.text;
NSString *filePath = [documentsPath stringByAppendingPathComponent:fileName];
NSData *audioData;
audioData = [[NSData alloc] initWithContentsOfFile:filePath];
[postBody appendData:audioData];
[postBody appendData:[#"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:#"--%#--\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postBody];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
And then I am trying to set up the delegate methods to handle the response:
#pragma mark NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSString *d = (NSString *)_responseData;
NSLog(d);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
}
When I look at what is being returned into the _responseData I'm not really sure what to do with it>
Printing description of self->_responseData: <7b224d65 73736167
65223a22 416e2065 72726f72 20686173 206f6363 75727265 642e227d>
I'm also not really sure if I've set up the request properly - I've just borrowed code that I've found here on StackOverflow without fully understanding it.
Any pointers direction more than welcome

iOS HTTP Post Redirection Handler Not Working

I am new to iOS development. I was just trying to do a post request to a server, but encountered problems mentioned here with server redirection. I used the event handler mentioned in the answer, but things still do not work right.
Here is my .m code:
#interface ViewController ()
#end
#implementation ViewController
#pragma mark NSURLConnection Delegate Methods
//CALL BACK METHODS
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#" didReceiveResponse");
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
//initialize response
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#" didReceiveData");
// Append the new data to the instance variable you declared
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#" connectionDidFinishLoading ");
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSString *dataReceived= [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
NSLog(#" async response data: %#", dataReceived);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#" didFailWithError");
// The request has failed for some reason!
// Check the error var
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *post = [NSString stringWithFormat:#"&j_username=%#&j_password=%#",#"usrname",#"pw"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
request = [[NSMutableURLRequest alloc] init];
request.HTTPMethod= #"POST";
//parameters
[request setURL:[NSURL URLWithString:#"url"]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"XMLHttpRequest" forHTTPHeaderField:#"X-Requested-With"];
[request setHTTPBody:postData];
// Send a synchronous request
if (0) {
NSURLResponse * response = nil;
NSError * error = nil;
NSData * data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
NSLog(#" Synchronous request done");
if (error == nil)
{
// Parse data here
NSLog(#" Synchronous response has no error");
NSLog(#" Synchronous Reply: %#", response);
}
}
else {
// Send Asynchronous request
//NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[NSURLConnection connectionWithRequest:request delegate:self];
NSLog(#" Asynchronous request sent");
}
}
- (NSURLRequest *)connection: (NSURLConnection *)connection
willSendRequest: (NSURLRequest *)inRequest
redirectResponse: (NSURLResponse *)redirectResponse;
{
if (redirectResponse) {
// we don't use the new request built for us, except for the URL
NSURL *newURL = [request URL];
NSString *redirectURL= [newURL absoluteString];
NSLog(#"Redirect URL: ");
NSLog(redirectURL);
// Previously, store the original request in _originalRequest.
// We rely on that here!
NSMutableURLRequest *newRequest = [request mutableCopy];
[newRequest setURL: newURL];
NSLog(#"redirect occur");
return newRequest;
} else {
NSLog(#"no redirect");
return inRequest;
}
}
#end
Without the handler, the request goes through fine(just without the body attached); but with the handler, the redirection gets detected again and again b/c the redirected url is same as the original. Eventually the requested died because of too many redirects. I think this might be a server end problem, but am I doing anything wrong in the coding that causes this?
Basically the problem was that the url of the redirectResponse wasn't where you were redirected to; it's still the same one you set in the original post method. That was why you were being redirected to the same url again and again.
So what you wanna do is intercepting the actual url you are being redirected to in the response headers. After your initial post request was executed, you should get response headers like this:
HTTP/1.1 302 Found
Location: http://www.iana.org/domains/example/
where "Location" indicates where you are being redirected to. So get the url like so:
NSDictionary* headers = [(NSHTTPURLResponse *)redirectResponse allHeaderFields];
NSString newUrl=headers[#"Location"];
Use newUrl in your newRequest, then you should be good to go.

ASIHTTPRequest + SBJSon iphone

I am working with an application where I have to request a url and I get the response accordingly
I am using ASIHTTPRequest to request the URL
here is my request
-(void)getTips {
if ([CommonFunctions networkConnected]) {
ShowNetworkActivityIndicator();
NSString *strPhp = #"staticpage.php";
NSString *strQuery = [[NSString alloc] initWithString:[NSString stringWithFormat:#"%#%#?static_id=3",GMS_URL,strPhp]];
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:strQuery]];
NSLog(#"tips url %#",request.url);
request.delegate = self;
[request setRequestMethod:#"GET"];
[request startAsynchronous];
}
}
These are my delegate methods
-(void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data {
// NSString *responseStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// NSLog(#"responseStr %#",responseStr);
SBJsonParser *json = [[SBJsonParser alloc]init];
NSLog(#"json data %#",[json objectWithData:data]);
NSMutableArray *marrData = [[json objectWithData:data] valueForKey:#"responseData"];
if([[marrData valueForKey:#"result"] isEqualToString:#"failed"]){
[CommonFunctions showAlertMessage:[marrData valueForKey:#"error"]];
}
HideNetworkActivityIndicator();
}
Here I get null data no matter whether I pass request methods GET or POST
When I check the same url in browser I get the response and a valid json from online json viewer
What are the possible reason that I am getting null data in the application
Use requestFinished: delegate.. Please try this.
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"response %#", [request responseString]);
}

Uploading large images using Base64 and JSON

I am using this function to upload an image to a server using JSON. In order to do so, I first convert the image to NSData and then to NSString using Base64. The method works fine when the image is not very large but when I try to upload a 2Mb image, it crashes.
The problem is that the server doesn't receive my image even though the didReceiveResponse method is called as well as the didReceiveData which returns (null). At first I thought it was a time out issue but even setting it to 1000.0 it still doesn't work. Any idea? Thanks for your time!
Here's my current code:
- (void) imageRequest {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.myurltouploadimage.com/services/v1/upload.json"]];
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:#"%#/design%i.png",docDir, designNum];
NSLog(#"%#",path);
NSData *imageData = UIImagePNGRepresentation([UIImage imageWithContentsOfFile:path]);
[Base64 initialize];
NSString *imageString = [Base64 encode:imageData];
NSArray *keys = [NSArray arrayWithObjects:#"design",nil];
NSArray *objects = [NSArray arrayWithObjects:imageString,nil];
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:kNilOptions error:&error];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d",[jsonData length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"Image uploaded");
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"didReceiveResponse");
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"%#",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}
I finally decided to upload the Base64 image splitting it into smaller substrings. In order to do so, and as I needed many NSURLConnections, I created a subclass named TagConnection which gives a tag for each connection so that there's no possible confusion between them.
Then I created a TagConnection property in MyViewController with the purpose of accessing it from any function. As you can see, there's the -startAsyncLoad:withTag: function that allocs and inits the TagConnection and the -connection:didReceiveData: one which deletes it when I receive a response from the server.
Referring to the -uploadImage function, firstly, it converts the image into string and then splits it and put the chunks inside the JSON request. It is called until the variable offset is larger than the string length which means that all the chunks have been uploaded.
You can also prove that every chunk has been successfully uploaded by checking the server response every time and only calling the -uploadImage function when it returns success.
I hope this has been a useful answer. Thanks.
TagConnection.h
#interface TagConnection : NSURLConnection {
NSString *tag;
}
#property (strong, nonatomic) NSString *tag;
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)tag;
#end
TagConnection.m
#import "TagConnection.h"
#implementation TagConnection
#synthesize tag;
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)tag {
self = [super initWithRequest:request delegate:delegate startImmediately:startImmediately];
if (self) {
self.tag = tag;
}
return self;
}
- (void)dealloc {
[tag release];
[super dealloc];
}
#end
MyViewController.h
#import "TagConnection.h"
#interface MyViewController : UIViewController
#property (strong, nonatomic) TagConnection *conn;
MyViewController.m
#import "MyViewController.h"
#interface MyViewController ()
#end
#synthesize conn;
bool stopSending = NO;
int chunkNum = 1;
int offset = 0;
- (IBAction) uploadImageButton:(id)sender {
[self uploadImage];
}
- (void) startAsyncLoad:(NSMutableURLRequest *)request withTag:(NSString *)tag {
self.conn = [[[TagConnection alloc] initWithRequest:request delegate:self startImmediately:YES tag:tag] autorelease];
}
- (void) uploadImage {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.mywebpage.com/upload.json"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:1000.0];
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:#"%#/design%i.png", docDir, designNum];
NSLog(#"%#",path);
NSData *imageData = UIImagePNGRepresentation([UIImage imageWithContentsOfFile:path]);
[Base64 initialize];
NSString *imageString = [Base64 encode:imageData];
NSUInteger length = [imageString length];
NSUInteger chunkSize = 1000;
NSUInteger thisChunkSize = length - offset > chunkSize ? chunkSize : length - offset;
NSString *chunk = [imageString substringWithRange:NSMakeRange(offset, thisChunkSize)];
offset += thisChunkSize;
NSArray *keys = [NSArray arrayWithObjects:#"design",#"design_id",#"fragment_id",nil];
NSArray *objects = [NSArray arrayWithObjects:chunk,#"design_id",[NSString stringWithFormat:#"%i", chunkNum],nil];
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:kNilOptions error:&error];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d",[jsonData length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:jsonData];
[self startAsyncLoad:request withTag:[NSString stringWithFormat:#"tag%i",chunkNum]];
if (offset > length) {
stopSending = YES;
}
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSError *error;
NSArray *responseData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if (!responseData) {
NSLog(#"Error parsing JSON: %#", error);
} else {
if (stopSending == NO) {
chunkNum++;
[self.conn cancel];
self.conn = nil;
[self uploadImage];
} else {
NSLog(#"---------Image sent---------");
}
}
}
#end
Please don't think this is the last option, this is just my observation.
I think you should send that NSData in chunks instead of complete Data.
I have seen such methodology in YouTube Video Uploading case.They send the Large set of NSData (NSData of Video File) in Chunks of many NSData.
They uses the Same Methodology for uploading the large data.
So should do google about the Youtube data Uploading API.And you should search out that method , YouTube Uploader Uses.
I hope it may help you .

Resources