Best practice when using similar code in methods - objective-c

I have a Utility method to comunicate with an API, it communicates using a POST HTTP request, in my utility-class i have a method called:
(void)makeConnectionWithParameters:(NSMutableDictionary*)parameters;
wich takes the parameters and sets up the body of the POST. however, in one particular case i want to upload some images and the code is slightly altered to make uploading of said images possible, what is the best practice for this case? should i rename the method to:
(void)makeConnectionWithParameters:(NSMutableDictionary*)parameters andImages(NSArray*)images;
and set nil as a parameter in all other cases, or should i set a bool in the method calling "makeConnectionWithParameters" and check in the method if the bool is set and in that case process the images?
Any other ideas to make the code prettier?
here is the method:
(void)makeConnectionWithParameters:(NSMutableDictionary*)parameters
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = [NSURL URLWithString:BASE_URL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLCacheStorageAllowed timeoutInterval:20];
request.HTTPMethod = #"POST";
NSString *boundary = #"myR4ND0Mboundary";
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#", boundary];
[request setValue:contentType forHTTPHeaderField: #"Content-Type"];
//Lägg till inloggningsuppgifter för API-anropet
[parameters setValue:API_LOGIN forKey:#"api-login"];
[parameters setValue:API_PASSWORD forKey:#"api-password"];
//Lägg till alla parameterar i POST-bodyn
NSMutableData *body = [NSMutableData data];
for (NSString *param in parameters)
{
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"%#\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"%#\r\n", [parameters objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
}
if(hasImages)
{
int c = 0;
for(UIImage* image in self.images)
{
c++;
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
if (imageData)
{
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"%#\"; filename=\"image.jpg\"\r\n", [NSString stringWithFormat:#"image%d", c]] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"Content-Type: image/jpeg\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[[NSString stringWithFormat:#"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
}
imageData = nil;
}
}
//Sätt content-length
NSString *postLength = [NSString stringWithFormat:#"%d", [body length]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:body];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if(connection)
{
receivedData = [NSMutableData dataWithLength:0];
}
}
I hope this all makes sense. :)

Simply create two methods that make the request objects, not the actual connections:
(NSMutableURLRequest*)makeConnectionWithParameters:(NSMutableDictionary*)parameters;
(NSMutableURLRequest*)makeConnectionWithParameters:(NSMutableDictionary*)parameters andImages(NSArray*)images;
Inside the first method call:
[self makeConnectionWithParameters:parameters andImages:nil];
...and have a nil check for the images inside the second method. Use those two methods to get your request then make the NSURLConnection with the returned object.

Related

- connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite: never call

I want to notify my user about the progress of the upload of some Mpeg 3 files. Just one.
but I get issue as I say in the title.
My upload code is here
- (NSString *) upload: (NSData*) postData {
NSString *str;
NSURL *url = [NSURL URLWithString:#"http://example.com/test.php"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
request.HTTPMethod = #"POST";
NSString *boundary = #"unique-consistent-string";
// set Content-Type in HTTP header
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#", boundary];
[request setValue:contentType forHTTPHeaderField: #"Content-Type"];
// post body
NSMutableData *body = [NSMutableData data];
// add params (all params are strings)
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
// add mp3 data
if (postData) {
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=%#; filename=audio\r\n", #"audioFormKey"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: audio/mpeg3\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:postData];
[body appendData:[[NSString stringWithFormat:#"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:#"--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
// setting the body of the post to the reqeust
[request setHTTPBody:body];
// set the content-length
NSString *postLength2 = [NSString stringWithFormat:#"%lu", (unsigned long)[body length]];
[request setValue:postLength2 forHTTPHeaderField:#"Content-Length"];
NSLog(postLength2);
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if(data.length > 0)
{
NSError *error;
NSURLResponse *response;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *str=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(str);
}
}];
return str;
}
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
NSLog(#"bytes transfer %li" ,(long)bytesWritten);
}
Here the Log "bytes transfer" is never call.
Thanks a lot for support
A bit odd to be calling sendAsynchronousRequest: and then sendSynchronousRequest: in the completion handler?
In any case, you aren't configuring the URL connection to have a delegate and, thus, your delegate method is never called.
You'll need to allocated and instantiate the URLConnection and then configure it to use your object as the delegate. And it needs to conform to the NSURLConnectionDelegate protocol.

Twitter API 1.1 - update_with_media returns 500

I'm trying to upload a picture on Twitter from a Mac app, using REST API 1.1 (url: https://api.twitter.com/1.1/statuses/update_with_media.json), but I get always error code 500 and {"errors":[{"message":"Internal error","code":131}]}.
If I upload only a tweet (using /update.json) it works fine every time.
Here is my code:
NSURL *url = [NSURL URLWithString:#"https://api.twitter.com/1.1/statuses/update_with_media.json"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0f];
[request setHTTPMethod:#"POST"];
[request setHTTPShouldHandleCookies:NO];
NSString *boundary = #"64F3EC90-E32B-4BD9-ADB4-E1A9FBE4AFD6";
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
[request setValue:contentType forHTTPHeaderField:#"Content-Type"];
[self signRequest:request]; // Adding Oauth
NSMutableData *body = [NSMutableData dataWithLength:0];
// Adding tweet string
[body appendData:[[NSString stringWithFormat:#"--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
NSData *data = [[NSString stringWithFormat:#"%#\r\n",#"Uploading again test3"]dataUsingEncoding:NSUTF8StringEncoding];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"%#\"\r\n",#"status"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:data];
// Adding image
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Disposition: form-data; name=\"media[]\"; filename=\"test.jpg\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: image/jpeg\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Transfer-Encoding: binary\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
// Set HTTPBody
[request setValue:#(body.length).stringValue forHTTPHeaderField:#"Content-Length"];
request.HTTPBody = body;
I had luck with the following code:
- (void)postTweet:(NSString *)tweetString withImageData:(NSData *)imageData {
NSURL *baseURL = [NSURL URLWithString:url_statuses_update_with_media];
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[#"status"] = tweetString;
params[#"media[]"] = imageData;
[self sendPOSTRequestForURL:baseURL andParams:params];}
-(NSError *)sendPOSTRequestForURL:(NSURL *)url andParams:(NSDictionary *)params {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0f];
[request setHTTPMethod:#"POST"];
[request setHTTPShouldHandleCookies:NO];
NSString *boundary = #"64F3EC90-E32B-4BD9-ADB4-E1A9FBE4AFD6";
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
[request setValue:contentType forHTTPHeaderField:#"Content-Type"];
[self signRequest:request];
NSMutableData *body = [NSMutableData dataWithLength:0];
for (NSString *key in params.allKeys) {
id obj = params[key];
[body appendData:[[NSString stringWithFormat:#"--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
NSData *data = nil;
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"%#\"\r\n",key] dataUsingEncoding:NSUTF8StringEncoding]];
if ([obj isKindOfClass:[NSData class]]) {
[body appendData:[#"Content-Type: application/octet-stream\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
data = (NSData *)obj;
} else if ([obj isKindOfClass:[NSString class]]) {
data = [[NSString stringWithFormat:#"%#",(NSString *)obj]dataUsingEncoding:NSUTF8StringEncoding];
}
[body appendData:[#"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:data];
[body appendData:[#"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:#"--%#--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setValue:#(body.length).stringValue forHTTPHeaderField:#"Content-Length"];
request.HTTPBody = body;

Uploading array of images(wrapped in NSData) to the server in iOS

Good day,
I'm trying to upload an array of images to the server, images are wrapped into NSData, but the server returning only one image, this is my code:
- (void)actionSave{
NSArray *imagesArray = [NSArray arrayWithObjects:[NSData dataWithData:UIImagePNGRepresentation(self.imageViewForImageOne.image)],
[NSData dataWithData:UIImagePNGRepresentation(self.imageViewForImageTwo.image)],
[NSData dataWithData:UIImagePNGRepresentation(self.imageViewForImageThree.image)],
[NSData dataWithData:UIImagePNGRepresentation(self.imageViewForImageFour.image)], nil];
NSData *images = [NSKeyedArchiver archivedDataWithRootObject:imagesArray];
NSMutableURLRequest *requestImg = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#&mid=%#", SEND_POST_TO_WALL, [self.currentFriend objectForKey:#"uid"]]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0f];
[requestImg setHTTPMethod:#"POST"];
NSString *boundary = #"---------------------------14737809831466499882746641449";
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#", boundary];
[requestImg addValue:contentType forHTTPHeaderField:#"Content-Type"];
NSMutableData *postData = [NSMutableData dataWithCapacity:[images length] + 512];
[postData setData:images];
NSMutableData *body = [NSMutableData data];
//Photo
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Disposition: form-data; name=\"image\"; filename=\"image.png\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:postData];
[body appendData:[#"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
//Text
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"text\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[self.textView.text dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[requestImg setHTTPBody:body];
NSURLConnection *connectionForImage = [NSURLConnection connectionWithRequest:requestImg delegate:self];
if (connectionForImage) {
self.infoData = [NSMutableData data];
} else {
NSLog(#"Connection failed");
}
}
This is the result that server returns:
array(3) {
["act"]=>
string(12) "comments.add"
["module"]=>
string(7) "account"
["mid"]=>
string(4) "7728"
}
POST:
array(1) {
["text"]=>
string(5) "Gjdgy"
}
FILES:
array(1) {
["image"]=>
array(5) {
["name"]=>
string(9) "image.png"
["type"]=>
string(10) "image/jpeg"
["tmp_name"]=>
string(14) "/tmp/php9oudKt"
["error"]=>
int(0)
["size"]=>
int(463652)
}
}
What I'm doing wrong???
Thanks in advance!
You showed us the POST of the data but not the GET of that data again, so not sure what you mean by "only returns one image". What its returning should be the exact same data blob you went up, which is the archive. You can test this by logging the size of what you send up with the size of what you get back - they should both be the same if the server is returning your original blob back (if its not, that's a web issue not an ios issue).
With the blob you get back from the web, you then need to NSKeyUnarchive it to get your original array of data items. The unraveling is the reverse of the raveling.

How to send JSON request to service with parameters in Objective-C

I'm creating a iPhone app, and im trying to figure out how to create a JSON request to the webservice that contains parameters. In Java this would look like this
HashMap<String, String> headers = new HashMap<String, String>();
JSONObject json = new JSONObject();
json.put("nid", null);
json.put("vocab", null);
json.put("inturl", testoverview);
json.put("mail", username); // something#gmail.com
json.put("md5pw", password); // donkeykong
headers.put("X-FBR-App", json.toString());
The header has to contain a JSON object and "X-FBR-App" before the service recognizes the request. How would this be implemented in Objective-C ?
USE Post method.try this
NSString *method = #"addProduct";
NSString *jsonstring=#"http://yourdomain.com/product_review_api/product-review.php?";
NSString *urlString = [NSString stringWithFormat:#"%#",jsonstring];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"POST"];
NSMutableData *body = [NSMutableData data];
// image file
NSData *imageData = UIImageJPEGRepresentation( labelimage, 0.8);
NSString *boundary = [NSString stringWithString:#"---------------------------14737809831466499882746641449"];
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
// parameter method
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"method\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[method dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
// parameter categoryid
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"category_id\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[selectedID dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithString:#"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
// now lets make the connection to the web
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
NSLog(#"%#",returnString);
NSDictionary *profile = (NSDictionary*)[returnString JSONValue];
NSLog(#"profile=%#", profile);
you can append all the parameters like this.
JSON isn't baked into iOS, but if you look at www.JSON.org there are a number of Objective-C frameworks that provide the required functionality. I have no experience with any of them so I can't make recommendations, but it is a good start to finding a solution.
Also look at this SO question post-data-through-json-webservices-in-iphone

Failing to POST NSData of PDF to server

I have an iPad application in which I need to send a server a PDF file, alongside two POST variables, a user ID and a job ID. I am using the code below to do this:
NSData *pdfData = [NSData dataWithContentsOfFile:currentPDFFileName];
NSData *validPDF = [[NSString stringWithString:#"%PDF"] dataUsingEncoding: NSASCIIStringEncoding];
if (!(pdfData && [[pdfData subdataWithRange:NSMakeRange(0, 4)] isEqualToData:validPDF]))
{
NSLog (#"Not valid");
}
NSLog (#"%#", currentPDFFileName);
NSLog (#"%#", [currentPDFFileName lastPathComponent]);
//create the body
NSMutableData *body = [NSMutableData data];
//create the POST vars
NSString *jobID = [NSString stringWithFormat:#"Content-Disposition: form-data; name=\"jobid\"\r\n\r\n%#", job.jobID];
NSString *userID = [NSString stringWithFormat:#"Content-Disposition: form-data; name=\"userid\"\r\n\r\n%#", delegate.userID];
NSString *pdf = [NSString stringWithFormat:#"Content-Disposition: form-data; name=\"image_file\"; filename=\"%#\"\r\n", [currentPDFFileName lastPathComponent]];
[body appendData:[[NSString stringWithFormat:#"--%#\r\n", #"----foo"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[jobID dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", #"----foo"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[userID dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", #"----foo"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[pdf dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: application/pdf\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:pdfData];
NSMutableURLRequest *pdfRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://example.com"]];
[pdfRequest setValue:#"multipart/form-data; boundary=----foo" forHTTPHeaderField:#"Content-type"];
[pdfRequest setHTTPMethod:#"POST"];
[pdfRequest setHTTPBody:body];
NSData *pdfDataReply;
NSURLResponse *pdfResponse;
NSError *pdfError;
pdfDataReply = [NSURLConnection sendSynchronousRequest:pdfRequest returningResponse:&pdfResponse error:&pdfError];
NSString *pdfResult = [[NSString alloc] initWithData:pdfDataReply encoding:NSASCIIStringEncoding];
NSLog (#"%#", pdfResult);
The people on the other end of the connection are saying that they are not receiving the PDF file. I have tried all the usual suspects such as trying to find any nil objects.
Would greatly appreciate if anyone could please lend a hand with this!
Thanks.
Ricky.
Turns out there was an issue with the boundaries. I needed to add one at the end, after pdfData was added. Thank you for your help.