Show the location options when manually searching location - iphone

In text field when user start typing the location name, i want to show the list of locations name below as the user type, similar to search field like starts with alphabet 'A' show all option of 'A'. How can this be achieved.
How can I get location names?
Please guide for the above. And if any other thing need to ask please feel free to ask.
Thanks in advance.

You need to use google api for that for sure.. Here is a link: https://developers.google.com/places/documentation/autocomplete
The Google Places Autocomplete API is a web service that returns Place information based on text search terms, and, optionally, geographic bounds. The API can be used to provide autocomplete functionality for text-based geographic searches, by returning Places such as businesses, addresses, and points of interest as a user types.
You need to create your API Key using https://code.google.com/apis/console/#project:18836829369. When you get your response you just need to look at predictions in your json response.
Hope this helps :)

You Should use google place API. I dont know much about that but this link will be helpful.
Remember this for location search not for autocomplete searchbar.

You can use the below given function :
- (void)searchText:(NSString *)substring
{
for (int i = 0; i < [yourArray count]; i++)
{
NSString *curString = [[yourArray objectAtIndex:i]lowercaseString];
NSString *searchString = [substring lowercaseString];
if ([curString rangeOfString:curStringSmall].location == NSNotFound)
{
}
else
{
//This means searched text is found in your array. you can store it in new array. Which will give you only the search criteria matched element.
}
}
}
You need to call this function from textFieldShouldBeginEditing :
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
[self searchText:txtSearch.text];
return YES;
}

Related

iOS - Amazon S3 Slow Download

I am creating an iOS app that allows users to write lets say a status update and people can comment on it, like it, interact with it in multiple ways, basically the status update has multiple properties that would be stored with it. Imagine an app with a home-screen of more than 50 of these status updates represented into a table view.
Now take your eyes away and focus on a practice/demo app, a developer trying to master the techniques before the big game (thats me!) So essentially, I have started out by setting up an S3 bucket based in Singapore. I live in Singapore, so there is a server nearby and really everything should be fast and smooth. Except, its just not. Its slow, and its starting to make me annoyed.
I know an app that uses S3 that loads high-definition panorama images with comments, likes etc. and it takes a second or a bit more for all this data to load. I am not sure how they actually carry out the process, I know they store the images on S3 but thats all I know. In my starter demo, I simply upload some pieces of text (say 20) then download them and it takes like 15 seconds under my 60 mbps wifi! These pieces of text don't even exceed a sentence each, they are phrases, so I am really kind of confused here.
I have CloudFront setup but isn't it for websites? I have the manage distributions and URL things all setup but how to setup in my code? This is probably my biggest question to nail down for release later in my other app. Even so, I live in Singapore and the bucket is in the Singapore server, so CloudFront for self-testing / practicing wouldn't be mandatory.
I find this extremely confusing, here is some annotated code I have produced, any problems, misconceptions that is leading it to be slow?
- (void)loadObjects {
S3ListObjectsRequest *listObjectRequest = [[S3ListObjectsRequest alloc] initWithName: #"testbucketquotes.rohanprostudios"];
S3ListObjectsResponse *listObjectResponse = [[AmazonClientManager s3] listObjects:listObjectRequest];
if(listObjectResponse.error != nil)
{
}
else
{
S3ListObjectsResult *listObjectsResults = listObjectResponse.listObjectsResult;
if (objects == nil) {
objects = [[NSMutableArray alloc] initWithCapacity:[listObjectsResults.objectSummaries count]];
}
else {
[objects removeAllObjects];
}
// By defrault, listObjects will only return 1000 keys
// This code will fetch all objects in bucket.
NSString *lastKey = #"";
for (S3ObjectSummary *objectSummary in listObjectsResults.objectSummaries) {
if ([[objectSummary key] rangeOfString: #"UploadedQuote"].location != NSNotFound) {
[objects addObject:[objectSummary key]];
lastKey = [objectSummary key];
}
}
while (listObjectsResults.isTruncated) {
listObjectRequest = [[S3ListObjectsRequest alloc] initWithName: #"testbucketquotes.rohanprostudios"];
listObjectRequest.marker = lastKey;
listObjectResponse = [[AmazonClientManager s3] listObjects:listObjectRequest];
if(listObjectResponse.error != nil)
{
break;
}
listObjectsResults = listObjectResponse.listObjectsResult;
for (S3ObjectSummary *objectSummary in listObjectsResults.objectSummaries) {
if ([[objectSummary key] rangeOfString: #"UploadedQuote"].location != NSNotFound) {
[objects addObject:[objectSummary key]];
}
lastKey = [objectSummary key];
}
}
if (objects.count) {
for (int i = 0; i <= objects.count - 1; i++) {
S3GetObjectRequest *req = [[S3GetObjectRequest alloc] initWithKey:[objects objectAtIndex: i] withBucket: #"testbucketquotes.rohanprostudios"];
`// asynchronously loads text (adds to operation queue)`
AsyncQuoteDownloader *quote = [[AsyncQuoteDownloader alloc] initWithRequest:req andViewController: self];
[operationQueue addOperation: quote];
// in 'AsyncQuoteDownloader' when finished calls a method in this view controller adding the response to an array and reloading a table
}
}
}
});
}
Anything wrong with my code that is making it lag so much? I would have thought this would take a matter of milliseconds if an imaging service would take 1 second to load HQ images with likes and comments etc takes 1-2 seconds.
Thank you for any help...
Update
Ok, so the iteration of keys doesn't seem to be the problem here but rather the downloading of the objects. Any thoughts? Thanks...
This is the first time I've ever even seen Objective C, so I may be completely wrong here. But... it looks like you're iterating through the keys of the entire bucket. This is going to be really, really slow with any appreciable quantity of keys.
A better design would be store a lookup table in something like DynamoDB (since you're already using AWS). You'd query there, get an array of matching id's (S3 keys), and then fetch the match objects from S3.
Another option, as I used in my own iOS app, is to use Heroku as the app layer and create a POSTGRESQL record that points to your content. This way you can create rich queries in rails and mediate upload and download with the power of Rails, rather then paying for both DynamoDB and S3.
Turns out my bucket was set to US region and not Singapore region... #doh
Its faster now, its working fine
I just needed to set the AmazonS3Client's endpoint to Singapore (SEA) region

combine UITextFields input into one UITtextField

Im new to xcode and objective c. I have asked this question three times and still can't find a good method or answer. I have several uitextfields that accept user input and adds it to the combinedtextField in order of IBAction used.ie user inputs big in one field,bad in the next one and boy in the third and the result is big bad boy in the combinedtextField.
-(IBAction)addtextField1: (id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text,textField1.text];
}
-(IBAction)addtextField2: (id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text, textField2.text];
}
-(IBAction)addtextField3:(id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text,textField3.text];
}
Now this is where it gets interesting.I need to be able to remove the selected text from the combinedtextField.
-(IBAction)removetextField1:(id)sender
{
//////////????????????////////////////
}
-(IBAction)removetextField2: (id)sender
{
//////////????????????////////////////
}
-(IBAction)removetextField3: (id)sender
{
//////////????????????////////////////
}
If I tap the removetextField2 button it would remove the corresponding text(bad) from the combinedtextField and then it would read (big boy)
Ive looked into nsarrays,nsdictionarys and other methods and have got no where.
Need some way of possibly tagging the input and removing it that way. Example code would be great and very much appreciated.
You've left out some important details about your app, so I'm making some guesses about how it should work.
Perhaps what you should do is keep a mutable array of all of the fragments that have been added to the combined string:
#implementation MyViewController {
    NSMutableArray *fragments_;
}
- (void)viewDidLoad {
[super viewDidLoad];
fragments_ = [[NSMutableArray alloc] init];
}
When one of the add buttons is tapped, you append the corresponding field's text to the array and recompute the combined string:
- (IBAction)addTextField1:(id)sender {
[fragments_ addObject:textField1.text];
[self updateCombinedTextField];
}
- (void)updateCombinedTextField {
combinedTextField.text = [fragments componentsJoinedByString:#" "];
}
When one of the remove buttons is tapped, you try to remove the corresponding field's text from the fragments array and recompute the combined string:
- (IBAction)removeTextField1:(id)sender {
[fragments_ removeObject:textField1.text];
[self updateCombinedTextField];
}
That will remove all occurrences of field 1's text from the fragments array. If you just want to remove one instance, you will need to use indexOfObject: (or one of its variants) followed by removeObjectAtIndex:.
You can't do it in a very trivial way (without anything to add, just 1stroke magic function). But, there's the easy way, which i'd possible gone for.
If you don't need to do it a lot of times, and / or the text is quite small (not like a 500 pages book), then:
Create a boolean array named mark, and mark[i] should mark the i'th text field as 'added'. Then, create a function named reloadCombinedTextField, which creates it again, depended of the mark array. (if mark[i] == true, then we add a textfield's text, otherwise not)
Then, just mark or unmark the needed text fields in every function and call the reload function in the end of every call.
Altho, there is another way, but it can be wrong in situations where your text fields have the same text. The thing is, you just search in your combined text field the text from selected text field (for example, with [NSString rangeOfString] method) and remove it.
If you are going to do it often and the text is really big, then it goes much more complicated. But i'm quite sure, that you won't do this on iOS.

iPhone/Objective-C - Searching for a specific word within a string

Is there a way to search for specific words within a string in Objective-C?
Let's say I have the following sentence:
thequickbrownfox
If I wanted to search for "quick" within the sentence. What would be the best way to achieve this?
Thanks for your help.
if ([myString rangeOfString:stringToSearch].location != NSNotFound) {
// stringToSearch is present in myString
}
You can use NSString::rangeOfString for this.
From the docs -
Return Value
An NSRange structure giving the location and length in the receiver of the first occurrence of aString. Returns {NSNotFound, 0} if aString is not found or is empty (#"").

How do I retrieve a page number or page reference for an Outline destination in a PDF on iOS?

I've been reading through the adobe pdf spec, along with apple's quartz 2d documentation for pdf rendering and parsing. I've also downloaded Voyeur and inspected a local pdf with it to see it's internal data. At this point I'm able to get the document catalog, and then fetch the outlines dictionary from there. I can see that nested within the outlines dictionary dictionaries that there are named "/Dest" nodes with values such as:
G1.1025588
etc
I'm wondering if there is a way for me to use these values to get a reference to page to render using some methods I've seen github projects such as Reader, along with apple documented examples.
PDF processing is definitely a challenge, so any help would be appreciated.
The /Dest entry in an outline item dictionary can either be a name, a string, or an array.
The simplest case is if it's an array; then the first item is the page object the outline entry points to (a dictionary). To get the page number, you have to iterate over all pages in the document and see which one is equal (==) to the dictionary you have (CGPDFPageRefs are actually CGPDFDictionaryRefs). You could also traverse the page tree, which is a bit harder, but may be faster (not as much as you might expect, I wouldn't optimize prematurely here). The other items in the array are position on the page etc., search for "Explicit Destinations" in the PDF spec to learn more.
If the entry is a name or string, it is a named destination. You have to map the name to a destination from the document catalog's /Dests entry which is a dictionary that contains a name tree. A name tree is essentially a tree map that allows fast access to named values without requiring to read all the data at once (as with a plain dictionary). Unfortunately, there's no direct support for name trees in Quartz, so you'll have to do a little more work to parse this structure recursively (see "Name Trees" in the PDF spec).
Note that an outline item doesn't necessarily have a /Dest entry, it can also specify its destination via an /A (action) entry, which is a little bit more complex. In most cases, however, the action will be a "GoTo" action that is essentially a wrapper for a destination.
The mapping of names to destinations can also be stored as a plain dictionary. In that case, it's in the /Dests entry of the /Names dictionary in the document's catalog. I've rarely seen this though and it was deprecated after PDF 1.2 (current is 1.7).
You will definitely need the PDF spec for this: http://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf
Thanks to Omz, here is a piece of code to retreive a page number for an outline destination in a PDF file :
// Get Page Number from an array
- (int) getPageNumberFromArray:(CGPDFArrayRef)array ofPdfDoc:(CGPDFDocumentRef)pdfDoc withNumberOfPages:(int)numberOfPages
{
int pageNumber = -1;
// Page number reference is the first element of array (el 0)
CGPDFDictionaryRef pageDic;
CGPDFArrayGetDictionary(array, 0, &pageDic);
// page searching
for (int p=1; p<=numberOfPages; p++)
{
CGPDFPageRef page = CGPDFDocumentGetPage(pdfDoc, p);
if (CGPDFPageGetDictionary(page) == pageDic)
{
pageNumber = p;
break;
}
}
return pageNumber;
}
// Get page number from an outline. Only support "Dest" and "A" entries
- (int) getPageNumber:(CGPDFDictionaryRef)node ofPdfDoc:(CGPDFDocumentRef)pdfDoc withNumberOfPages:(int)numberOfPages
{
int pageNumber = -1;
CGPDFArrayRef destArray;
CGPDFDictionaryRef dicoActions;
if(CGPDFDictionaryGetArray(node, "Dest", &destArray))
{
pageNumber = [self getPageNumberFromArray:destArray ofPdfDoc:pdfDoc withNumberOfPages:numberOfPages];
}
else if(CGPDFDictionaryGetDictionary(node, "A", &dicoActions))
{
const char * typeOfActionConstChar;
CGPDFDictionaryGetName(dicoActions, "S", &typeOfActionConstChar);
NSString * typeOfAction = [NSString stringWithUTF8String:typeOfActionConstChar];
if([typeOfAction isEqualToString:#"GoTo"]) // only support "GoTo" entry. See PDF spec p653
{
CGPDFArrayRef dArray;
if(CGPDFDictionaryGetArray(dicoActions, "D", &dArray))
{
pageNumber = [self getPageNumberFromArray:dArray ofPdfDoc:pdfDoc withNumberOfPages:numberOfPages];
}
}
}
return pageNumber;
}

if-query: if (Nslog isEqualtoString #"...") - How can I make this?

I want my app to do something when the last NSLog has a certain string. I thought I could realize this with an if-query and isEqualtoString, but how can I make this?
Sorry for my bad English ;)
Maybe I don't understand what you're trying to do, but you can just create the string somewhere, log it, and then test it:
NSInteger _someInt = 2;
NSString *_someString = #"bananas";
NSString *_stringToBeLogged = [NSString stringWithFormat:#"%d %#", _someInt, _someString];
NSLog(#"%#", _stringToBeLogged);
if ([_stringToBeLogged isEqualToString:#"2 bananas"]) {
NSLog(#"I logged two bananas...");
}
You could consider creating your own custom log function which calls NSLog() after checking for your string constant. This would keep your code a bit cleaner if you want this functionality in multiple places and also allows you to easily extend the logging function further if desired.