NSMutableRequest and Flickr API for upload images - iphone

I use Flickr API for my app to manage user's photo. I decided to make authentication using Apple's classes and it works fine for me. Now my app is authenticated and has all necessary tokens and secret keys so it's possible to perform GET requests with authentication for methods like flickr.photos.search, flickr.test.login and so on.
But I spent a few days trying to perform upload using http://api.flickr.com/services/upload/
and their instructions here.
They say that request should have argument 'photo' and this parameter should not be included in the signature. That is clear, but I have no idea how to implement this parameter the request.
#import "FlickrUploader.h"
#import "HMACSH1.h"
#import "Prefs.h"
#import "NSString+URLEncode.h"
#implementation FlickrUploader
- (void)uploadPhotoAtPath:(NSString*)filePath {
NSString *upload_api_url = #"http://api.flickr.com/services/upload/";
NSString *oauth_nonce = [NSString stringWithFormat:#"%d", 10000000 + arc4random()%1000000];
NSString *oauth_timestamp = [NSString stringWithFormat:#"%d", (long)[[NSDate date] timeIntervalSince1970]];
NSString *oauth_consumer_key = CONSUMER_KEY;
NSString *oauth_signature_method = #"HMAC-SHA1";
NSString *oauth_version = #"1.0";
NSString *oauth_token = [[NSUserDefaults standardUserDefaults] objectForKey:OAUTH_ACCESS_TOKEN_KEY];
//creating basestring to make signature without a 'photo' argument according to API
NSMutableString *basestring = [[NSMutableString alloc] initWithCapacity:8];
[basestring appendFormat:#"&oauth_consumer_key=%#",oauth_consumer_key];
[basestring appendFormat:#"&oauth_nonce=%#",oauth_nonce];
[basestring appendFormat:#"&oauth_signature_method=%#",oauth_signature_method];
[basestring appendFormat:#"&oauth_timestamp=%#",oauth_timestamp];
[basestring appendFormat:#"&oauth_token=%#", oauth_token];
[basestring appendFormat:#"&oauth_version=%#",oauth_version];
//this is may class to make HMAC-SHA1 signature (it works for authentication and for GET requests)
HMACSH1 *hMACSH1 = [[HMACSH1 alloc] init];
NSMutableString *urlEncodedBaseString = [[NSMutableString alloc] initWithCapacity:3];
[urlEncodedBaseString appendString:#"POST"];
[urlEncodedBaseString appendFormat:#"&%#",[upload_api_url urlEncodedString]];
[urlEncodedBaseString appendFormat:#"&%#",[basestring urlEncodedString]];
NSString *oauth_token_secret = [[NSUserDefaults standardUserDefaults] objectForKey:OAUTH_TOKEN_SECRET_KEY];
NSString *hash_key = [CONSUMER_SECRET stringByAppendingFormat:#"&%#",oauth_token_secret];
NSString *oauth_signature = [hMACSH1 hmacSH1base64ForData:urlEncodedBaseString keyValue:hash_key];
//creating url for request
NSMutableString *urlString = [[NSMutableString alloc] initWithCapacity:8];
[urlString appendFormat:#"%#",upload_api_url];
[urlString appendFormat:#"?"];
[urlString appendString:basestring];
[urlString appendFormat:#"&oauth_signature=%#", oauth_signature];
NSURL *authURL = [[NSURL alloc] initWithString:urlString];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:authURL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
request.HTTPMethod = #"POST";
UIImage *img = [UIImage imageNamed:filePath];
NSData *imgData = UIImageJPEGRepresentation(img, 0.8);
//here I don't know what to do :((( perhaps NSOutputStream
}

Related

Send NSURLConnection request multiple times with different url's in a for loop

I have an array of addresses that I need to convert to Lat/Long using Google's Geocode api. I am feeding an address and the city into the Google Geocode URL, which forms a correct connection url.
Basically I want to be able to use a for loop to create multiple NSURLConnection requests, returning multiple responses.
-(void)setString{
for (int i = 0; i < [businessArray count]; i ++)
{
NSString *address = [addressArray objectAtIndex:0];
NSString *city = [locationDict valueForKey:#"city"];
NSString *geocodeURL = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#,+%#,&sensor=true", address, city];
geocodeURL = [geocodeURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:geocodeURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10];
NSLog(#"%#", request);
geoCodeConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if (geoCodeConnection)
{
responseData = [NSMutableData data];
connectionIsActive = YES;
NSLog(#"connection active");
} else {
NSLog(#"connection failed");
connectionIsActive = NO;
}
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSError *jsonError = nil;
SBJsonParser *json = [[SBJsonParser alloc] init];
NSDictionary *parsedJSON = [json objectWithString:responseString error:&jsonError];
NSString *lat= [[[[parsedJSON valueForKey:#"results"] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lat"];
NSString *lng= [[[[parsedJSON valueForKey:#"results"] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lng"];
NSLog(#"lat = %# long= %#", lat, lng);
connectionIsActive = NO;
[geoCodeLatArray addObject:lat];
[geoCodeLngArray addObject:lng];
NSLog(#"geoCodeArrayLat: %#", geoCodeLatArray);
}
Right now the code returns only the last address' lat and long. How can I send multiply requests and return multiply responses with JSON?
Try this I am using this,
for(int i=0;i< businessArray.count;i++)
{
NSString *address = [addressArray objectAtIndex:i];
NSString *city = [locationDict valueForKey:#"city"];
NSString *address = [NSString stringWithFormat:#"%#,%#", address, city];
CLLocationCoordinate2D location = [self geoCodeUsingAddress:address];
// then here store the location.latitude in lat array and location.longitude in long array.
}
- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address
{
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSDictionary *googleResponse = [[NSString stringWithContentsOfURL: [NSURL URLWithString: req] encoding: NSUTF8StringEncoding error: NULL] JSONValue];
NSDictionary *resultsDict = [googleResponse valueForKey: #"results"];
NSDictionary *geometryDict = [resultsDict valueForKey: #"geometry"];
NSDictionary *locationDict = [geometryDict valueForKey: #"location"];
NSArray *latArray = [locationDict valueForKey: #"lat"];
NSString *latString = [latArray lastObject];
NSArray *lngArray = [locationDict valueForKey: #"lng"];
NSString *lngString = [lngArray lastObject];
CLLocationCoordinate2D location;
location.latitude = [latString doubleValue];
location.longitude = [lngString doubleValue];
return location;
}
Update to the above function:
- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address
{
double latitude = 0, longitude = 0;
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
if (result) {
NSScanner *scanner = [NSScanner scannerWithString:result];
if ([scanner scanUpToString:#"\"lat\" :" intoString:nil] && [scanner scanString:#"\"lat\" :" intoString:nil]) {
[scanner scanDouble:&latitude];
if ([scanner scanUpToString:#"\"lng\" :" intoString:nil] && [scanner scanString:#"\"lng\" :" intoString:nil]) {
[scanner scanDouble:&longitude];
}
}
}
CLLocationCoordinate2D location;
location.latitude = latitude;
location.longitude = longitude;
return location;
}
This worked for me.
You might approach the problem using an asynchronous method that performs the request and has a completion block which will be called when the result is available. This completion block provides a parameter result which is the result of the connection request.
This method may be declared as follows:
typedef void (^completion_block_t) (id result);
- (void) fetchGeoCoordinateForAddress:(NSString*)address
completionHandler:(completion_block_t)completionHandler;
Say, if the request succeeds the parameter result in the block is a JSON representation of the response data. Otherwise, result is an NSError object indicating the error. But the exact details depend on how you implement the method fetchGeoCoordinateForAddress:completionHandler:.
Now you can setup the loop as follows:
for (NSString* address in addresses)
{
[self fetchGeoCoordinateForAddress:address completionHandler:^(id result) {
if (![result isKindOfError:[NSError class]]) // check if result is an error
{
// Note: result is not nil and is a NSDictionary representation of JSON.
// Retrieve the "location" from the response:
NSDictionary* location = result[#"results"][#"geometry"][#"location"];
// Multiple request can occur at the same time! Thus, we need to
// synchronize access to the result array "myLocations" through
// accessing it *exclusively and everywhere* on the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
[self.myLocations addObject:location];
});
}
else {
// got error
DebugLog(#"ERROR: %#", result);
}
}
}
Note: your actual code may differ slightly depending on the actual JSON and other details.
Regarding the implementation of method fetchGeoCoordinateForAddress:completionHandler: you have a few options:
Use a third party library and implement a simple convenience wrapper fetchGeoCoordinateForAddress:completionHandler:.
Create your own "MyHTTPConnectionOperation" class that encapsulates a NSURLConnection and the response data and couple of other useful state info in a dedicated class. This class executes the request asynchronously via start method and has a completion handler. Basically, all third party network libraries will use this approach. Then implement the wrapper.
Use NSURLConnection's asynchronous convenient method if it is sufficient and works in your context. This is the fastest to implement, but least flexible approach and may not work in all cases and may also work only suboptimal.
Edit:
A couple of hints:
If possible, use NSJSONSerialization for parsing JSON and creating a Foundation representation. Other third party libraries only offer a slight advantage if you have special requirements, e.g. you need "chunked parsing with NSData objects" - which is useful when you want to download and parse simultaneously. Or you need to create other representations than Foundation - say a C++ container or you want directly create a Model with SAX style parsing. Or, you need better performance and lower memory food print since you are receiving ultra large strings which you want to save to disk. NSJSONSerialization became quite fast recently, so "performance" alone shouldn't be an argument today.
The timeout for the request shall be not that low as 10 seconds. In a cellular connection, this is too less. Leave it at the default.
If you plan to implement your own "HTTPConnectionOperation" class, I've put a very limited sample on gist here which can give you a jump start.
I think you have to start with AFNetworking
AFNetworking1
AFNetworking2
because AFNetworking gives a lot of power and flexibility in terms of scheduling and queueing requests as well as pausing and cancelling requests.

How To get Sender E-mail from Device?

I am sending some data from my application to server. my data consist of different fields as my code shown below
-(void)createXML
{
xmlStr = #"<?xml version='1.0'?>\n<jand_req>\n<inquiryList>\n<productArr>\n";
NSString *nameStr=[NSString stringWithFormat:#"<name>%#</name>\n",name.text];
xmlStr=[xmlStr stringByAppendingString:nameStr];
NSString *compNameStr=[NSString stringWithFormat:#"<comp_name>%#</comp_name>\n",compName.text];
xmlStr=[xmlStr stringByAppendingString:compNameStr];
NSString *cityStr=[NSString stringWithFormat:#"<city>%#</city>\n",city.text];
xmlStr=[xmlStr stringByAppendingString:cityStr];
NSString *countryStr=[NSString stringWithFormat:#"<country>%#</country>\n",[nameToCode objectForKey:country.text]];
xmlStr=[xmlStr stringByAppendingString:countryStr];
NSString *commentsStr=[NSString stringWithFormat:#"<comment>%#</comment>\n",commentsBox.text];
xmlStr=[xmlStr stringByAppendingString:commentsStr];
xmlStr=[xmlStr stringByAppendingString:#"</userDetail>\n</inquiryList>\n</jand_req>"];
}
After this i send the above data to server as my code shown below
- (void)submitForm
{
[self createXML];
NSLog(#"myaccesscode%#",[fn getValFromSettings:#"accessCode"]);
NSString *serviceUrlStr=[NSString stringWithFormat:#"%#/%#/API_sendmail.php?access_code=%#",domainName,apiFolderPath,[fn getValFromSettings:#"accessCode"]];
NSLog(#"%#",serviceUrlStr);
NSURL * serviceUrl = [NSURL URLWithString:[serviceUrlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest * serviceRequest = [NSMutableURLRequest requestWithURL:serviceUrl cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:100];
[serviceRequest setValue:#"text/xml" forHTTPHeaderField:#"Content-type"];
[serviceRequest setHTTPMethod:#"POST"];
[serviceRequest setHTTPBody:[xmlStr dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *conn=[[[NSURLConnection alloc] initWithRequest:serviceRequest delegate:self startImmediately:YES] autorelease];
}
All the above code works fine for me but now i want to include an another feature in this code Which consist of sender E-mail address but this sender E-mail must be fetch from device same as when we use MFMailComposeViewController in application then automatically it gets sender E-mail Address from Device.Any help will be appriated thanks.
#import <AddressBook/AddressBook.h>
NSString *emailAddr = #"";
ABPerson *aPerson = [[ABAddressBook sharedAddressBook] me];
ABMultiValue *emails = [aPerson valueForProperty:kABEmailProperty];
if([emails count] > 0)
emailAddr = [emails valueAtIndex:0];
don't forget to add AddressBook.framework.
Now, the emailAddr contains the senders email which you can append to your xml string or wherever you want it to!
-(void)createXML
{
// Your code
NSString *emailStr=[NSString stringWithFormat:#"<email>%#</email>\n",emailAddr];
xmlStr=[xmlStr stringByAppendingString:emailStr];
}
happy coding!

How to handle Spanish character in my App?

In my app i have a service which supports spanish and return the result in spanish.
Now i am trying to pass some search term to this service to get the result back but its failing because while sending compiler converts the word to some funny word with unidentified characters.
I am doing this:
name here is coming in spanish but when i am adding this in the config dictionary it gets converted again to some funny thing.
-(void)perfromLocationSearchWithName:(NSString *)name{
NSData * nameCode = [[NSData alloc]init];
nameCode = [name dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString * namePass = [[NSString alloc]initWithData:nameCode encoding:NSUTF8StringEncoding];
NSLog(#"Name:%#",namePass);
NSMutableDictionary *config = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease];
NSString * strAction = [NSString stringWithFormat:#"vendorSearchByName"];
if (namePass !=nil){
[config setObject:namePass forKey:#"vendorName"];
//[config setObject:#"001" forKey:#"MakeCode"];
[config setObject:#"5" forKey:#"maxCount"];
[config setObject:strAction forKey:#"action"];
}
NSLog(#"Dict%#",[config description]);
comm = [[CommManager alloc] init];
[comm searchDealerLocationWithOptions:config withDelegate:self];
[namePass release];
}
Please help
Thanks,
Try using NSISOLatin1StringEncoding. Helped us in our app.

Travel Application Airport code returns City,Country

I am trying to develop an travel application.I would like to submit the Airport code and get back the Country,City, along with the weather of that particular space.Is there an API out in the market that will help me in doing that???Or is there some other way I can do that?
Here's one for the city/country: http://airportcode.riobard.com/about
and this question has good info about weather: Weather API - Provides "About to..." Information?
Here's a sample piece of code that accepts the text from 'inputTextField' and outputs the location to 'outputLabel'
-(IBAction)getCity{
NSString *urlString = [NSString stringWithFormat:#"http://airportcode.riobard.com/airport/%#?fmt=json",self.inputTextField.text];
NSURL *url = [NSURL URLWithString:urlString];
NSString *response = [[NSString alloc] initWithContentsOfURL:url];
const char *convert = [response UTF8String];
NSString *responseString = [NSString stringWithUTF8String:convert];
NSDictionary *airport = [responseString JSONValue];
self.outputLabel.text=[airport objectForKey:#"location"];
}

function to get the file name of an URL

I have some source code to get the file name of an url
for example:
http://www.google.com/a.pdf
I hope to get a.pdf
because the way to join 2 NSStrings I can get is 'appendString' which only for adding a string at right side, so I planned to check each char one by one from the right side of string 'http://www.google.com/a.pdf', when it reach at the char '/', stop the checking, return string fdp.a , after that I change fdp.a to a.pdf
source codes are below
-(NSMutableString *) getSubStringAfterH : originalString:(NSString *)s0
{
NSInteger i,l;
l=[s0 length];
NSMutableString *h=[[NSMutableString alloc] init];
NSMutableString *ttt=[[NSMutableString alloc] init ];
for(i=l-1;i>=0;i--) //check each char one by one from the right side of string 'http://www.google.com/a.pdf', when it reach at the char '/', stop
{
ttt=[s0 substringWithRange:NSMakeRange(i, 1)];
if([ttt isEqualToString:#"/"])
{
break;
}
else
{
[h appendString:ttt];
}
}
[ttt release];
NSMutableString *h1=[[[NSMutableString alloc] initWithFormat:#""] autorelease];
for (i=[h length]-1;i>=0;i--)
{
NSMutableString *t1=[[NSMutableString alloc] init ];
t1=[h substringWithRange:NSMakeRange(i, 1)];
[h1 appendString:t1];
[t1 release];
}
[h release];
return h1;
}
h1 can reuturn the coorect string a.pdf, but if it returns to the codes where it was called, after a while system reports
'double free
*** set a breakpoint in malloc_error_break to debug'
I checked a long time and foudn that if I removed the code
ttt=[s0 substringWithRange:NSMakeRange(i, 1)];
everything will be Ok (of course getSubStringAfterH can not returns the corrent result I expected.), no error reported.
I try to fix the bug a few hours, but still no clue.
Welcome any comment
Thanks
interdev
The following line does the job if url is a NSString:
NSString *filename = [url lastPathComponent];
If url is a NSURL, then the following does the job:
NSString *filename = [[url path] lastPathComponent];
Try this:
Edit: from blow comment
NSString *url = #"http://www.google.com/a.pdf";
NSArray *parts = [url componentsSeparatedByString:#"/"];
NSString *filename = [parts lastObject];
I think if you have already had the NSURL object, there is lastPathComponent method available from the iOS 4 onwards.
NSURL *url = [NSURL URLWithString:#"http://www.google.com/a.pdf"];
NSString *filename = [url lastPathComponent];
Swift 3
Let's say that your url is http://www.google.com/a.pdf
let filename = url.lastPathComponent
\\filename = "a.pdf"
This is more error free and meant for getting the localized name in the URL.
NSString *localizedName = nil;
[url getResourceValue:&localizedName forKey:NSURLLocalizedNameKey error:NULL];
I haven't tried this yet, but it seems like you might be trying to do this the hard way. The iPhone libraries have the NSURL class, and I imagine that you could simply do:
NSString *url = [NSURL URLWithString:#"http://www.google.com/a.pdf"];
NSString *path = [url path];
Definitely look for a built in function. The libraries have far more testing and will handle the edge cases better than anything you or I will write in an hour or two (generally speaking).