I want search result like Google search.
Here if I search for 'tokyo' then it gives me four results containing place 'tokyo'.
Same functionality I want to do using Foursquare API. Currently I am able to find near places from current position or given position.
You need to use the https://api.foursquare.com/v2/venues/search endpoint and use the query parameter so that it will return matches based on your keyword. Since you're on iOS you can use UITableView to show the results as search suggestions or other libraries that fit your requirement. Since it will be like an autocomplete/autosuggest search, I suggest that you try to call the endpoint on the change event of the text field with a delay.
Example using AFNetworking Library for iOS:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:FOURSQUARE_CLIENTID forKey:#"client_id"];
[params setObject:FOURSQUARE_CLIENTSECRET forKey:#"client_secret"];
[params setObject:searchTextField.text forKey:#"query"];
[params setObject:LatLong forKey:#"ll"];
[params setObject:FOURSQUARE_VERSION forKey:#"v"];
[manager GET:#"https://api.foursquare.com/v2/venues/search" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
//Process the JSON response here and output each venue name as search suggestion
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
I suggest you read more on the FourSquare documentation and how to process JSON results and show them to a UITableView if you don't know how to yet.
Also notice that you still have to provide your "ll" as parameter since you can only query for nearby places using the endpoint.
For global search and not using "ll" or "nearby" parameter. You can try to use the global intent which according to the documentation:
Finds the most globally relevant venues for the search, independent of
location. Ignores all other parameters other than query and limit.
Related
Having this issue, because I'm trying to develop my code. Before, I was using AFNetworking methods in the classes, but I got 4 of them. Instead of that repeatin sequence, I wanted to have APIClient, which has the methods. I implemented some methods but my issue is about just two of them.
So, in APIClient.m I have the followings:
+(void)GetCurrencyInformationFrom:(NSString *)URLString to:(NSArray *) array inThe:(UITableView *) tableView{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; // User informations.
NSString *accessToken = [defaults objectForKey:#"accessToken"];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:accessToken forHTTPHeaderField:#"Token"];
NSLog(#"access token: %#", accessToken);
NSLog(#"id: %#", [defaults objectForKey:#"ID"]);
[manager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[self update:array withDictionary:responseObject inThe:tableView];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error 2: %#", error);
}];
}
+(void)update:(NSArray *)array withDictionary:(NSDictionary *)dictionary inThe:(UITableView *) tableView{
NSLog(#"Data Count: %lu", [dictionary[#"Data"] count]);
array = [[NSMutableArray alloc] initWithArray:dictionary[#"Data"]];
NSLog(#"Array Count: %lu", [array count]);
[tableView reloadData];
}
Those methods are called in Table View classes. For example, one of my classes I called within the viewload those:
NSString *URL = #"http://api-dvzalt.azurewebsites.net/api/Currency/Doviz";
[APIClient GetCurrencyInformationFrom:URL to:currencyArray inThe: tableView];
For debugging, I am printing the Data count and Array count (Both you can find in update:withDictionary:inThe: method) and number of rows (in the table class). It's normal to number of rows to be zero at the beginning since it is asychronous, however, after I reload my tableView, i.e. after everything is done (see [tableView reloatData] in update:withDictionary:inThe method) number of rows remains zero, where Data and Array's count are 20. And of course, with zero rows, nothing showed up on the table. So, basically my problem is the currencyArray I'm giving to method doesn't change after it comes back to the tableView again even it is changing in the APIClient class.
I feel like it is a simple mistake, but I can't see where it is. Glad if you can help me to find it.
Thanks!
Did you make sure that your UITableView has the correct data source set?
What do your -numberOfSectionsInTableView: and -tableView:numberOfRowsInSection: methods look like?
I don't really like answering my question. However in this case, I bet there are too many newbie people around and searching for the same problem I have. I couldn't find any solution for 4 days. Have been searching on net and asking here, but nowhere I found the solution I needed. Maybe it will be not the case for you, but certainly it will at least take 1 day long, if it is the first time. So, I will give a try to make beginners like me understand deeply.
At first, creating and having a class like APIClient is generally a good idea. It is just a class that you can easily use when you are going to take data from internet. However, things are getting complicated for beginners since we are mostly got used to synchronous execution.
If you are up trying modify your any instance in any class, what you have to do is, simply, not to give that instance to APIClient (or the class that has blocks) like me, instead trying to take any needed information from the APIClient. Like, if we can achieve the information coming from the APIClient, it is easy to that instance in the instance's own class. E.g. giving currencyArray to APIClient, and trying to update the array in APIClient is hard. On the other hand, it is easy to just taking the responceObject from APIClient, which will be exactly the JSON data coming from the URL you have.
Long story short, in that manner, I changed my code in the APIClient.m into this:
+(void)GetCurrencyInformationFrom:(NSString *)URLString to:(NSArray *) array inThe:(UITableView *) tableView{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; // User informations.
NSString *accessToken = [defaults objectForKey:#"accessToken"];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:accessToken forHTTPHeaderField:#"Token"];
NSLog(#"access token: %#", accessToken);
NSLog(#"id: %#", [defaults objectForKey:#"ID"]);
[manager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if(success) success(operation, responseObject)
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if(failure) failure(operation, error)
}];
}
Note that I have no longer update:withDictionary:inThe: method, since the plan is taking the information to the instance's class, and update it there. not here.
For updating purpose, let's call in the viewLoad of the instance's class. So, the method will look like this:
[APIClient GetCurrencyInformationFrom:URL
success:^(AFHTTPRequestOperation *operation, id responseObject) {
[self updateCurrencyArrayWithDictionary:responseObject];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error 2: %#", error);
}];
Again for updating purpose, I also added update method here instead of APIClient, which is not really necessary actually; instead we would have block type instance.
-(void)updateCurrencyArrayWithDictionary:(NSDictionary *)dictionary{
currencyArray= [[NSMutableArray alloc] initWithArray:dictionary[#"Data"]];
[tableView reloadData];
}
Please note that the line dictionary[#"Data"]]; would probably change according to your data.
So, that's it. This is just a simple example of how to create API client for the networking purpose of our application.
Hope, I can help someone in the future with this post.
I am having an issue parsing two JSON urls at once. YouTube only permits 50 results per request, so I'd like to add a second with a start-index of 51, to continue the request.
NSString *urlAsString = #"https://gdata.youtube.com/feeds/api/playlists/PLgw1uRYia2CRvuF4Y3KLuvFSWY6lmuY8T?v=2&alt=json&max-results=50&orderby=published";
NSString *urlAsString2 = #"https://gdata.youtube.com/feeds/api/playlists/PLgw1uRYia2CTSBBNrTDjdEcswVFjPkCr9?v=2&alt=json&max-results=50&orderby=published";
Combining two of them, I tried this:
NSString *finallink = [NSString stringWithFormat:#"%#,%#", urlAsString, urlAsString2];
Then making the actual request with Afnetworking, I added:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:finallink parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSDictionary *feed = [[NSDictionary alloc] initWithDictionary:[responseObject valueForKey:#"feed"]];
videoArray = [NSMutableArray arrayWithArray:[feed valueForKey:#"entry"]];
[self.videoMetaData addObjectsFromArray:[videoArray valueForKeyPath:#"title.$t"]];
operation.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/html"];
[self.videolist reloadData];
[self->activityind startAnimating];
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Videos"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
NSLog(#"Error: %#", error);
}];
This does not work for some reason. I get this error:
Error: Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)"
What could be wrong?!
As mentioned in the comments, this code fails because you are trying to retrieve the result of two URLs joined to one another. The way it is set up now is equivalent to trying to visit http://google.com,http://google.com in a web browser, which will of course fail.
Instead, the solution is to retrieve the results in batches, one after the other. Here's one way to do it:
Write a method which retrieves the YouTube results at a given offset. If you want to retrieve all links starting at 51, then a good idea would be to have a method which takes an offset and returns the results in a completion block.
Write another method which can use the previous one to retrieve the entire list of results. This will need to send multiple network requests to YouTube, one for each batch of 50 that you need, and collect the results somewhere.
There are a couple other issues I noticed in your code sample. One is that you are setting a new request and response serializer in the success block of your network request – instead, you should set these once somewhere in your app, because reallocating them after each request is inefficient. AFHTTPRequestOperationManager does create default instances of these, so you can get away with not setting them at all.
Another potential issue is that you are displaying an alert view in your failure block. Because AFNetworking performs network requests on a background thread by default (from what I recall), you might run into some weird problems (the usual symptom is that your UI will not show up for a few seconds). Apple requires that UI-related methods are called on the main thread.
I've been using AFNetworking for a while and ran into a bizarre issue today.
I'm do a GET request using AFNetworking with Google Places API
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=21.283974,-157.836222&radius=1600&types=food|bar|cafe&key=myownapikeyhere
the places nearby search api uses type restriction to constrain the result you can get from the api. see document
the way you do it is to have parameter types=type1|type2|type3|etc, the type1, type2, type3 are the types of places you want fetch with the url.
I managed to get results when I paste the url into browser and request it. but whenever I use it with AFNetworking, the '|' sign seems to break it. It throws an unsupported url error.
Is there a reason with this issue? Any suggestion would be helpful.
Thanks!
Are you building this URL yourself? If you used the parameters of a AFNetworking GET request, I believe it would percent escape it properly. But if you build the URL yourself, you're not letting AFNetworking do the necessary percent escaping.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *params = #{#"location" : #"21.283974,-157.836222",
#"radius" : #1600,
#"types" : #"food|bar|cafe",
#"key" : #"myownapikeyhere"};
[manager GET:#"https://maps.googleapis.com/maps/api/place/nearbysearch/json" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"responseObject = %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error = %#", error);
}];
It is too simple. Just replace the | with %7C
NSString *string = #"https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=21.283974,-157.836222&radius=1600&types=food|bar|cafe&key=myownapikeyhere";
NSString *newString = [string stringByReplacingOccurrencesOfString:#"|" withString:#"%7C"];
I would like to know how to store profile picture in sign up screen where is 1 UIImageView and few Uitextfields. My problem is, that I don't know how to select picture from camera or photo library and choose one which will be upload to parse database. Second problem is that I am not able to retrieve this photo to UIImageView. I wasn't able to find any tutorial to this. If anyone knows something helpful I would appreciate that.
A nice tutorial that is going to show you how to create a login service and upload a profile picture representing the user : http://www.raywenderlich.com/13511/how-to-create-an-app-like-instagram-with-a-web-service-backend-part-12
For picking an image you'll have to use UIImagePickerController, for uploading it, you'll have to convert the image into a PFFile and thus upload it.
Here's a great tutorial that might help you:
https://www.youtube.com/watch?v=Q6kTw_cK3zY
In addition to this tutorial, look into his channel for a tutorial where he "upgrades" and also adding profile images
You can form data using post method By creating key value pair for all field and also set image Base64 image data in one key value pair. Example
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"foo": #"bar"};
[manager POST:#"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Over the last few days I've been struggling to get Google Places autocomplete to work on my app, and no matter what I do, I always get the REQUEST_DENIED error.
I followed Google's "tutorial" for the implementation, Places API is enabled, API key has the correct bundle ID, I also tested with a Browser ID, with no success.
I am pretty sure it has something to do with the key, though. Curiously, on the Android version of the app, the service will work with the Browser Key. And on the browser, obviously, it works with that key too.
These are the two keys I experimented with:
And this is my implementation code, using AFNetworking:
NSURL *url = [NSURL URLWithString:#"https://maps.googleapis.com/maps/api/place/autocomplete/"];
NSDictionary *params = #{#"input" : [input stringByReplacingOccurrencesOfString:#" " withString:#"+"],
#"location" : [NSString stringWithFormat:#"%f,%f", searchCoordinate.latitude, searchCoordinate.longitude],
#"sensor" : #(true),
// #"language" : #"pt_BR",
// #"types" : #"(regions)",
// #"components" : #"components=country:br",
#"key" : GOOGLE_API_KEY};
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
[httpClient setParameterEncoding:AFFormURLParameterEncoding];
[httpClient getPath:#"json"
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *JSON = [[NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:nil] dictionaryWithoutNulls];
if (completion) {
completion(JSON[#"predictions"]);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *errorResponse) {
NSLog(#"[HTTPClient Error]: %# for URL %#", [errorResponse localizedDescription], [[[operation request] URL] path]);
}];
I know there are some questions like this one here, but some are old, and say that Places API does not work on Android or iOS, which clearly is not the case anymore, since Google itself publishes examples on both platforms, as seen on Places API page: https://developers.google.com/places/documentation/autocomplete
A workaround I'm currently using is Apple's GeoCoding system, which works good when you type the full address, but is terrible with half-typed phrases. This is not good at all, I'd really like to use Google's API.
I got it!
The paramenter sensor should receive either #"true"or #"false", and not #(true)or #(false).
For the record, the API key used is indeed the Browser Key, and not an iOS key.
You should init httpClient with base URL #"https://maps.googleapis.com/" and get path /maps/api/place/autocomplete/json. Base URL - host only, it does not take other parts of path, so in your case you get request to URL "https://maps.googleapis.com/json".
https://maps.googleapis.com/maps/api/geocode/json?address="%#","%#"&sensor=false,yourAddress,your c