How to throttle search (based on typing speed) in iOS UISearchBar?
Thanks to this link, I found a very quick and clean approach. Compared to Nirmit's answer it lacks the "loading indicator", however it wins in terms of number of lines of code and does not require additional controls. I first added the dispatch_cancelable_block.h
file to my project (from this repo), then defined the following class variable: __block dispatch_cancelable_block_t searchBlock;
.
My search code now looks like this:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchBlock != nil) {
//We cancel the currently scheduled block
cancel_block(searchBlock);
}
searchBlock = dispatch_after_delay(searchBlockDelay, ^{
//We "enqueue" this block with a certain delay. It will be canceled if the user types faster than the delay, otherwise it will be executed after the specified delay
[self loadPlacesAutocompleteForInput:searchText];
});
}
Notes:
- The
loadPlacesAutocompleteForInput
is part of the LPGoogleFunctions library searchBlockDelay
is defined as follows outside of the@implementation
:static CGFloat searchBlockDelay = 0.2;
Live search throttle in Swift 3
Your error was because you probably forgot the #selector()
part.
Here's how it should look:
func searchBar() {
NSObject.cancelPreviousPerformRequests(withTarget: self,
selector: #selector(self.getSearch(completed:searchString:)),
object: nil)
perform(#selector(self.getSearch(completed:searchString:)),
with: nil, afterDelay: 0.5) }
You get the error because you didn't enclose your function in #selector
Now, as for the arguments, here's a function for that:
perform(#selector(getSearch:completion:searchString), with: <some completion>, with: "search string")
Search word by word to API
An effective way to do this is to monitor how long of a delay there is between user input, and only request to the server after the user has stopped typing for x amount of time.
For instance, the user types 'B' and waits 0.05 seconds then types 'o' and waits 0.08 seconds then types 'y' and stops typing.
If your code only submits to the server after there has been at least 0.5 seconds between character input, it will only request to the server once, after "Boy" has been entered.
How to detect that textDidChange: on UISearchBar was triggered by dictation
I had the same problem: detect that speech dictation is still running and processing the voice input.
It's exactly like you are describing: from the textDidChange you get an empty NSString with length=1
In my case, my solution was to take the first char of the text (if available) and check it's integer value. Apparently, the value of the "processing voice input" is always -17,
I know that is not a perfect solution, but it works. If someone has a better solution, please share it :)
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
BOOL atLeastOneChar = searchText.length > 0;
BOOL speechRecognitionOngoing;
if (atLeastOneChar) {
// Checking if the user used the dictation feature.
// A char of value -17 is always returned as text while processing the voice.
// So if the first char is == -17 it means the dictationg is going on.
const char firstChar = *text.UTF8String;
NSInteger processingDictationSpeechChar = -17;
if (firstChar == processingDictationSpeechChar) {
// --> speech recognition is ongoing!
speechRecognitionOngoing = YES;
}
}
}
iOS: Wait until user finishes typing and then send request
Add a small delay before sending the request, and then cancel that delayed request if the user continues typing
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSelector:@selector(sendSearchRequest) withObject:searchText afterDelay:0.1f];
}
you may need to adjust the delay time. too long and its noticeable to the user that there is a delay, too short and you have the same problem as now
Make UISearchBar to search on two different fields
There is a easy way to filter your array where you could decide completely when a object of the array should be in the new array or not:
data = data.filter({( aObject: YourClass) -> Bool in
// code for checking if the aObject should be in the data array
// then return true if it should be in the new array and false if not
// For example your return statement could be something like this:
return (aObject.firstString.lowercaseString.rangeOfString(searchText.lowercaseString) != nil) || (aObject.secondString.lowercaseString.rangeOfString(searchText.lowercaseString) != nil)
})
IOS: Autocomplete Search using UISearchbar
There are many logic but i put my logic here :
Take Two NSMutableArray
and add one array to another array in ViewDidLoad
method such like,
self.listOfTemArray = [[NSMutableArray alloc] init]; // array no - 1
self.ItemOfMainArray = [[NSMutableArray alloc] initWithObjects:@"YorArrayList", nil]; // array no - 2
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray]; // add 2array to 1 array
And Write following delegate Method of UISearchBar
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText
{
NSString *name = @"";
NSString *firstLetter = @"";
if (self.listOfTemArray.count > 0)
[self.listOfTemArray removeAllObjects];
if ([searchText length] > 0)
{
for (int i = 0; i < [self.ItemOfMainArray count] ; i = i+1)
{
name = [self.ItemOfMainArray objectAtIndex:i];
if (name.length >= searchText.length)
{
firstLetter = [name substringWithRange:NSMakeRange(0, [searchText length])];
//NSLog(@"%@",firstLetter);
if( [firstLetter caseInsensitiveCompare:searchText] == NSOrderedSame )
{
// strings are equal except for possibly case
[self.listOfTemArray addObject: [self.ItemOfMainArray objectAtIndex:i]];
NSLog(@"=========> %@",self.listOfTemArray);
}
}
}
}
else
{
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray ];
}
[self.tblView reloadData];
}
}
Output Show in your Consol.
This code might helpful for you.
Related Topics
Steps to Upload an iPhone Application to the Appstore
Uilabel Wrong Word Wrap in iOS 11
Metal - Resize Video Buffer Before Passing to Custom Kernel Filter
Making a Button Persistent Across All View Controllers
Uicollectionview Adding Image to a Cell
Where to Store Global Constants in an iOS Application
Implement Document Picker in Swift (Ios)
How to Implement Uipageviewcontroller That Utilizes Multiple Viewcontrollers
Entitlements File Do Not Match Those Specified in Your Provisioning Profile.(0Xe8008016)
How to Know If Cellular Access for My iOS App Is Disabled
The Executable Gets Signed with Invalid Entitlements in Xcode
Xcode 8 :Function Types Cannot Have Argument Label Breaking My Build
How to Dismiss Uialertcontroller When Tap Outside the Uialertcontroller
@Binding and Foreach in Swiftui
Ios9 - This Application Is Modifying the Autolayout Engine from a Background Thread -- Where
Wkwebview Open Links from Certain Domain in Safari
Ios 8.1 Simulator Always Uses Us Keyboard Layout Despite German Hardware Keyboard