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
Related
I am writing a photo upload queue manager.
Here is my process. The user can take a picture or choose one from the camera roll.
The image, along with some other string data, is placed in queue.
The queue is simply an array that contains the image path string and the other string data. The 'queued' image is saved to the documents directory of the application for later retrieval.
Every second the queue is checked to see if any images that need to be uploaded, then it does so, one-by-one.
When it uploads, the server responds with a string of success, if success then the picture is removed from list queue, the temp image is deleted and the program moves on to the next queued image.
If I call the uploadImage: method independently and pass it the image and string data, the image uploads fine. But when called from a background thread, the image is never truly uploaded even though the server responds success instantly. I feel like since the server is responding instantly with success, that the image is only partially being uploaded.
processImage: is the method that calls uploadImage: from the background.
I could really use an expert's eyes to see what might be causing the app to not fully wait on the photo to upload before continuing.
#interface ImageUploader ()
#property (nonatomic, strong) NSMutableArray * arrPhotoQueue;
#property (nonatomic, strong) NSTimer* timerUpload;
#end
#implementation ImageUploader {
NSUserDefaults * defaults; //Just were we are currently storing a list of images.
NSArray *paths;
NSString *documentsDirectory;
}
#pragma mark Public Methods
- (void) startPhotoUploadCheck {
if (!_timerUpload) {
if(![_timerUpload isValid]){
_timerUpload = [NSTimer scheduledTimerWithTimeInterval:_timerCheckInterval target:self selector:#selector(checkForPhotosToUpload) userInfo:nil repeats:YES];
}
}
}
- (void) addImageToQueue:(UIImage*)image withCallKey:(NSString*) callKey {
NSData *imageData = UIImagePNGRepresentation(image);
NSString *fileName = [NSString stringWithFormat:#"%#.png",[self randomStringWithLength:8]];
NSString *imagePath =[documentsDirectory stringByAppendingPathComponent:fileName];
NSMutableDictionary * data = [[NSMutableDictionary alloc] init];
[data setValue:fileName forKey:#"imagePath"];
[data setValue:callKey forKey:#"callKey"];
[_arrPhotoQueue addObject:data];
if (![imageData writeToFile:imagePath atomically:NO]) {
NSLog(#"Failed to cache image data to disk");
} else {
NSLog(#"Image %#", fileName);
[defaults setObject:_arrPhotoQueue forKey:#"PendingPhotos"];
[defaults synchronize];
}
[self totalImagesInQueue];
}
- (void) checkForPhotosToUpload {
//this does some logic to just see if there is a connection to the internet and that there are photos in queue then it calls
[self proceedWithUpload];
}
#pragma mark Upload Image
- (int) removePhotoFromMemory:(NSString *) callKeyOfUploadedPhoto
{
int nIndexOfUploadedPhoto = -1;
for (int i = 0; i < [_arrPhotoQueue count]; i++) {
NSString * callKey = [_arrPhotoQueue[i] objectForKey:#"callKey"];
if ([callKey isEqualToString:callKeyOfUploadedPhoto]) {
//remove uploaded photo
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:[_arrPhotoQueue[i] objectForKey:#"imagePath"]];
NSLog(#"Remove image from queue: %#", [_arrPhotoQueue[i] objectForKey:#"imagePath"]);
[[NSFileManager defaultManager] removeItemAtPath:imagePath error:nil];
nIndexOfUploadedPhoto = i;
break;
}
}
return nIndexOfUploadedPhoto;
}
- (void) proceedWithUpload {
NSMutableArray* removeArray = [[NSMutableArray alloc] init];
dispatch_group_t taskGroup = dispatch_group_create();
for (int i = 0; i < [_arrPhotoQueue count]; i++) {
dispatch_group_enter(taskGroup);
UIImage * image = [UIImage imageWithContentsOfFile:[_arrPhotoQueue[i] objectForKey:#"imagePath"]];
NSString * callKey = [_arrPhotoQueue[i] objectForKey:#"callKey"];
[self processImage:image :callKey completed:^(bool bSuccess){
if (bSuccess) {
//photo is uploaded successfully
int nPhotoIdx = [self removePhotoFromMemory:callKey];
if (nPhotoIdx > -1) {
[removeArray addObject:[NSString stringWithFormat:#"%d", nPhotoIdx]];
}
dispatch_group_leave(taskGroup);
} else {
dispatch_group_leave(taskGroup);
}
}];
}
// Here we wait for all the requests to finish
dispatch_group_notify(taskGroup, dispatch_get_main_queue(), ^{
// run code when all files are downloaded
[self removePhotoFromQueue:removeArray];
});
}
- (void) removePhotoFromQueue:(NSMutableArray*)index {
NSArray *sortedIndex = [index sortedArrayUsingComparator:^(id obj1, id obj2){
if ([obj1 isKindOfClass:[NSString class]] && [obj2 isKindOfClass:[NSString class]]) {
int nFirstIndex = (int)[obj1 integerValue];
int nSecondIndex = (int)[obj2 integerValue];
if (nFirstIndex > nSecondIndex) {
return (NSComparisonResult)NSOrderedAscending;
} else if (nFirstIndex < nSecondIndex) {
return (NSComparisonResult)NSOrderedDescending;
}
}
return (NSComparisonResult)NSOrderedSame;
}];
for (int i =0; i < [sortedIndex count]; i++) {
int nIdx = (int)[sortedIndex[i] integerValue];
[_arrPhotoQueue removeObjectAtIndex:nIdx];
}
[defaults removeObjectForKey:#"PendingPhotos"];
[defaults setObject:_arrPhotoQueue forKey:#"PendingPhotos"];
[defaults synchronize];
}
#pragma mark Image Processor
- (void) processImage:(UIImage*)image :(NSString*)callKey completed:(void(^)(bool bSuccess)) block{
__block NSMutableDictionary * message;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
message = [self uploadImage:image CallKey:callKey];
[self uploadImage:image CallKey:callKey];
dispatch_async(dispatch_get_main_queue(), ^{
if ([[message objectForKey:#"status"] isEqualToString:#"success"]) {
block(true);
} else {
NSLog(#"Somethign is wrong");
block(false);
}
});
});
}
- (NSMutableDictionary*) uploadImage:(UIImage *)theimage CallKey:(NSString*)callKey {
NSData * imageData = UIImageJPEGRepresentation([self fixrotation:theimage], 90);
NSString * jsonString= [JSONCommunicator buildJSONForImageUpload:[self prepareDictionaryDataForUploadWithKey:callKey]];
NSURL * uploadURL = [NSURL URLWithString:MYURL];
// create the URL
NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:uploadURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
[postRequest setHTTPMethod:#"POST"];
// just some random text that will never occur in the body
NSString *boundary = #"---------------------------14737809831466499882746641449";
NSString *headerBoundary = [NSString stringWithFormat:#"multipart/form-data; boundary=%#", boundary];
[postRequest addValue:headerBoundary forHTTPHeaderField:#"Content-Type"];
// create data
NSMutableData *postBody = [NSMutableData data];
// JSON part
[postBody appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[#"Content-Disposition: form-data; name=\"params\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[#"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// media part
[postBody appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"UploadedFile\"; filename=\"image.jpg\"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[#"Content-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:imageData];
[postBody appendData:[[NSString stringWithFormat:#"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
// final boundary
[postBody appendData:[[NSString stringWithFormat:#"--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
NSString *s = [[NSString alloc] initWithData:postBody encoding:NSASCIIStringEncoding];
//NSLog(#"Image String: %#", s);
// add body to post
[postRequest setHTTPBody:postBody];
// pointers to some necessary objects
NSURLResponse* response;
NSError* error;
// synchronous filling of data from HTTP POST response
NSData *responseData = [NSURLConnection sendSynchronousRequest:postRequest returningResponse:&response error:&error];
if (error) {
NSLog(#"Error: %#", [error localizedDescription]);
}
// convert data into string
NSString *responseString = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding:NSUTF8StringEncoding];
NSLog(#"TOPS Response String: %#", responseString);
NSData *data = [responseString dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary * dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
return dictionary;
}
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]);
}
I have 2 separate NSURLConnection.
NSURLConnection * connection_users;
NSURLConnection * connection_cards;
Then i created the data with parameters, etc. and I finish with:
connection_users = [[NSURLConnection alloc] initWithRequest: url_request_users delegate: self startImmediately: YES];
In the delegate method:
- (void) connection: (NSURLConnection *) connection didReceiveData: (NSData *) data
i Checked if the connection is for the connection_users:
if (connection == connection_users) / / do something as an example:
NSDictionary * json_response = [NSJSONSerialization JSONObjectWithData: data options: kNilOptions error: & error];
Use the "data" that came from the method.
Before closing the "if" I create the next connection to "connection_cards", doing the same things
Out of "if" but within the same method I do another "if" to "connection_cards" and do the same thing with JSONObjectWithData.
Only the "data" that comes from the method is always of the first connection.
What is happening differently? For the second connection was initiated then you should receive the "data" corresponding.
Already canceled the first connection before starting the second to see if solved, but no.
How to obtain the "data" correct for second connection?
PS: if you need more codes, please let me know.
EDITED:
As Wain ask
url_request_users = [[NSMutableURLRequest alloc] init];
NSMutableString *post_users = [[NSMutableString alloc] init];
[post_users appendFormat:#"%#", [NSString stringWithFormat:#"email=%#&senha=%#",
[[alert textFieldAtIndex:0] text],
senha_md5]];
[url_request_users setURL:[NSURL URLWithString:WBS_USERS_RECOVER]];
[url_request_users addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[url_request_users setHTTPMethod:#"POST"];
[url_request_users setHTTPBody:[post_users dataUsingEncoding:NSUTF8StringEncoding]];
connection_users = [[NSURLConnection alloc] initWithRequest:url_request_users delegate:self startImmediately:YES];
For n different connections you will need n different NSMutableData which contains result of related NSURLConnection. A basic example for your question;
NSMutableData *data_users;
NSMutableData *data_cards;
Than on your didRecieveData;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (connection == connection_users) {
[data_users appendData:data];
} else if ( connection == connection_cards) {
[data_cards appendData:data];
}
}
This way you can keep track of your data's and connection's seperately. Remember to clear leftovers for your datas when your connection is over
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (connection == connection_users) {
// use data from data_users
NSDictionary * json_response = [NSJSONSerialization JSONObjectWithData:[data_users copy] options: kNilOptions error: & error];
data_users = [[NSMutableData alloc] init]; // clear data users
}
// do the same for cards connection
}
Last thing to do is to allocate your data before you call this function;
url_request_users = [[NSMutableURLRequest alloc] init];
NSMutableString *post_users = [[NSMutableString alloc] init];
[post_users appendFormat:#"%#", [NSString stringWithFormat:#"email=%#&senha=%#",
[[alert textFieldAtIndex:0] text],
senha_md5]];
[url_request_users setURL:[NSURL URLWithString:WBS_USERS_RECOVER]];
[url_request_users addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[url_request_users setHTTPMethod:#"POST"];
[url_request_users setHTTPBody:[post_users dataUsingEncoding:NSUTF8StringEncoding]];
data_users = [[NSMutableData alloc] init]; // add this line in your code
connection_users = [[NSURLConnection alloc] initWithRequest:url_request_users delegate:self startImmediately:YES];
UPDATE: Apparently on iOS 5 the problem is the "Chunked-Encoding", When sending without that everything works. Seems on server that for some reason on iOS 5 the transfer never ends (on iOS 6 everything works). Anyone has a way around that?
I'm using NSURLConnection which works perfectly on iOS 6 and on simulator on same version, But when testing that on earlier devices I get response with only
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
and never with
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
Which suppose to contain my relevant data.
Here is a snippet of my code with all functions I've used (I saw that for some people removing some delegate function solved similar issue but in my case I don't have them):
-(void)establishConnection{
NSURL *url;
url = .... // Here I've set my url - it's https
self.responseData = [[NSMutableData alloc] initWithLength:0] ;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:SERVER_RESPONSE_TIMEOUT];
[request setHTTPMethod:#"POST"];
// More settings here //
....
//Accept-Language: ENUS
[request addValue:#"ENUS" forHTTPHeaderField:#"Accept-Language"];
// "Accept-Topic: Dictation"
[request addValue:#"Dictation" forHTTPHeaderField:#"Accept-Topic"];
// "Accept: text/plain"
[request addValue:#"text/plain" forHTTPHeaderField:#"Accept"];
//"Transfer-Encoding: chunked"
[request addValue:#"chunked" forHTTPHeaderField:#"Transfer-Encoding"];
NSMutableData *postBody = [NSMutableData data];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [NSString stringWithFormat:#"%#",[paths objectAtIndex:0]]; // Get sound directory
NSData *soundData = [NSData dataWithContentsOfFile: [NSString stringWithFormat:#"%#/%#",documentsDirectory, #"rec.wav"]];
[postBody appendData:soundData];
[postBody appendData:[#"\r\n" dataUsingEncoding: NSUTF8StringEncoding]];
// final boundary
//[postBody appendData:[[NSString stringWithFormat:#"--%#\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
// add body to post
[request setHTTPBody:postBody];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// You may have received an HTTP 200 here, or not...
NSLog(#"didReceiveResponse");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString* aStr = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"This is my first chunk %#", aStr);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connectionV {
connectionV = nil;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Something went wrong...");
}
Please help I can't find what am I doing wrong.
You should not set Transfer-Encoding chunked yourself. NSURLConnection will set this for you when it is appropriate.
Basically, a HTTP message requires either a Content-Length header set, or it uses chunked transfer encoding where no Content-Length header must be set.
When you set the body data as a stream via request's property HTTPBodyStream AND do NOT specify the Content-Length explicitly, NSURLConnection will automatically use chunked transfer encoding and basing its decision when the body data is finished on the stream's state (detecting EOF).
Otherwise, if you set the body data via property HTTPBody with a NSData object, you might set the Content-Length explicitly, or let NSURLConnection set it for you, based on the length of the NSData object. In that case, you don't get a chunked transfer encoding.
Otherwise, if you set your body data as a stream (say a NSInputStream which you created as a file stream) AND set the Content-Length header explicitly, NSURLConnection will NOT use chunked transfer encoding.
If possible, do set the Content-Length even for an NSInputStream, that is when you are able to know in advance how large the body is. There might be servers which have trouble or are simply not capable to parse data transmitted via chunked transfer encoding, e.g. Rails with a "simple server" like WEBrick when you send JSON or XML data. Otherwise, the web server will buffer all input data anyway.
I've been using the SimplePost classes for several weeks and haven't had any problems. Now I'm crashing after a Request returns proper data in a Connection. I haven't (knowingly) touched the SimplePost class files. But when I run the analyzer, it now (never did before) points out the following method:
+ (NSMutableURLRequest *) urlencodedRequestWithURL:(NSURL *)url andDataDictionary:(NSDictionary *) dictionary {
// Create POST request
NSMutableURLRequest *urlencodedPostRequest = [NSMutableURLRequest requestWithURL:url];
[urlencodedPostRequest setHTTPMethod:#"POST"];
// Add HTTP header info
[urlencodedPostRequest addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField: #"Content-Type"];
// Add POST body
NSMutableData *POSTBody = [NSMutableData data];
// Add k/v to the body
NSArray *keyArray = [dictionary allKeys];
for( int i = 0; i < [keyArray count]; ++i ) {
// Core Foundation function used to transform # ==> %40 , etc
NSString *escapedString = (__bridge NSString *) CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)([dictionary objectForKey:[keyArray objectAtIndex:i]]),NULL, (CFStringRef)#"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8);
[POSTBody appendData:[[NSString stringWithFormat:#"%#=%#", [keyArray objectAtIndex:i], escapedString] dataUsingEncoding:NSUTF8StringEncoding]];
if( i < ([keyArray count] - 1) ) {
[POSTBody appendData:[[NSString stringWithFormat:#"&"] dataUsingEncoding:NSUTF8StringEncoding]];
}
}
[urlencodedPostRequest setHTTPBody:POSTBody];
return urlencodedPostRequest;
}
And running the Analyzer shows me:
the lines continue as:
I'm having a hard time understanding what's happening. Can anyone help, please? Thanks!
Have you tried the __bridge_transfer for escapedString?
NSString *escapedString = (__bridge_transfer NSString *) CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)([dictionary objectForKey:[keyArray objectAtIndex:i]]),NULL, (CFStringRef)#"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8);
cf. Correct bridging for ARC?