UISearchBar class provides a text field for entering text, a search button, a bookmark button, and a cancel button. With the help of the
UISearchBarDelegate protocol you can implement the actions that will perform search on a database locally or send a request to the remote server when text is entered or buttons are clicked. In this example we implement the search bar to find a country by its name. The search request is sent to the remote server where a Java Servlet performs a simple query over the MySQL database to return a JSON array that is then displayed to the user using the Table view.
Java Servlet backend for remote search - CountrySearch.java
package com.as400samplecode;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import com.as400samplecode.util.Country;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
public class CountrySearch extends HttpServlet {
private static final long serialVersionUID = 1L;
public CountrySearch() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
//check of query data is sent
String queryString = request.getParameter("queryString");
if(queryString == null){
queryString = "";
}
//get list of countries and prepare JSON array to send back
ArrayList<Country> countryList = new ArrayList<Country>();
Connection conn = null;
PreparedStatement stmt = null;
String sql = null;
try {
Context ctx = (Context) new InitialContext().lookup("java:comp/env");
conn = ((DataSource) ctx.lookup("jdbc/mysql")).getConnection();
sql = "Select * from country where code <> 'CIV' ";
if(!queryString.trim().equals("")){
sql += "and lcase(name) like ?";
}
stmt = conn.prepareStatement(sql);
if(!queryString.trim().equals("")){
stmt.setString(1, "%" + queryString.trim().toLowerCase() + "%" );
}
ResultSet rs = stmt.executeQuery();
while(rs.next()){
Country country = new Country();
country.setCode(rs.getString("code").trim());
country.setName(rs.getString("name").trim());
countryList.add(country);
}
rs.close();
stmt.close();
stmt = null;
conn.close();
conn = null;
}
catch(Exception e){
e.printStackTrace();
}
finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlex) {
// ignore -- as we can't do anything about it here
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException sqlex) {
// ignore -- as we can't do anything about it here
}
conn = null;
}
}
Gson gson = new Gson();
JsonObject myObj = new JsonObject();
myObj.add("countryList", gson.toJsonTree(countryList));
myObj.addProperty("success", true);
out.println(myObj.toString());
}
}
Interface file for the App Delegate - MySearchBarAppDelegate.h
#import <UIKit/UIKit.h>
@class MySearchBarViewController;
@interface MySearchBarAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) MySearchBarViewController *viewController;
@end
Implementation file for the App Delegate - MySearchBarAppDelegate.m
#import "MySearchBarAppDelegate.h"
#import "MySearchBarViewController.h"
@implementation MySearchBarAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[MySearchBarViewController alloc]
initWithNibName:@"MySearchBarViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
Interface file for the UISearchBar View Controller - MySearchBarViewController.h
#import <UIKit/UIKit.h>
@interface MySearchBarViewController : UIViewController <UISearchBarDelegate,
UITableViewDelegate,UITableViewDataSource>
@property (nonatomic, strong) UISearchBar *mySearchBar;
@property (nonatomic, strong) UITableView *myTableView;
@property (nonatomic, strong) NSMutableArray *countryList;
@property (nonatomic, strong) NSString *queryString;
@end
Implementation file for the UISearchBar View Controller - MySearchBarViewController.m
#import "MySearchBarViewController.h"
@interface MySearchBarViewController ()
@end
@implementation MySearchBarViewController
@synthesize mySearchBar;
@synthesize myTableView;
@synthesize countryList;
@synthesize queryString;
- (void)viewDidLoad
{
[super viewDidLoad];
//create a search bar and add to the top of the screen
CGRect myFrame = CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y,
self.view.bounds.size.width, 44.0f);
self.mySearchBar = [[UISearchBar alloc] initWithFrame:myFrame];
//set the delegate to self so we can listen for events
self.mySearchBar.delegate = self;
//display the cancel button next to the search bar
self.mySearchBar.showsCancelButton = YES;
//add the search bar to the view
[self.view addSubview:self.mySearchBar];
//set the frame for the table view
myFrame.origin.y += 44;
myFrame.size.height = self.view.bounds.size.height - 44;
self.myTableView = [[UITableView alloc] initWithFrame:myFrame
style:UITableViewStylePlain];
//set the table view delegate and the data source
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
//set table view resize attribute
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
//set background view and color
self.myTableView.backgroundColor = [UIColor whiteColor];
self.myTableView.backgroundView = nil;
//add table view to the main view
[self.view addSubview:self.myTableView];
//execute the search without any query to display all countries
[self handleSearch:self.mySearchBar];
}
//search button was tapped
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self handleSearch:searchBar];
}
//user finished editing the search text
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
[self handleSearch:searchBar];
}
//do our search on the remote server using HTTP request
- (void)handleSearch:(UISearchBar *)searchBar {
//check what was passed as the query String and get rid of the keyboard
NSLog(@"User searched for %@", searchBar.text);
self.queryString = searchBar.text;
[searchBar resignFirstResponder];
//setup the remote server URI
NSString *hostServer = @"http://demo.mysamplecode.com/Servlets_JSP/";
NSString *myUrlString = [NSString stringWithFormat:@"%@CountrySearch",hostServer];
//pass the query String in the body of the HTTP post
NSString *body;
if(self.queryString){
body = [NSString stringWithFormat:@"queryString=%@", self.queryString];
}
NSURL *myUrl = [NSURL URLWithString:myUrlString];
//make the HTTP request
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:myUrl];
[urlRequest setTimeoutInterval:60.0f];
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
//we got something in reponse to our request lets go ahead and process this
if ([data length] >0 && error == nil){
[self parseResponse:data];
}
else if ([data length] == 0 && error == nil){
NSLog(@"Empty Response, not sure why?");
}
else if (error != nil){
NSLog(@"Not again, what is the error = %@", error);
}
}];
}
//parse our JSON response from the server and load the NSMutableArray of countries
- (void) parseResponse:(NSData *) data {
NSString *myData = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"JSON data = %@", myData);
NSError *error = nil;
id jsonObject = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:&error];
if (jsonObject != nil && error == nil){
NSLog(@"Successfully deserialized...");
NSNumber *success = [jsonObject objectForKey:@"success"];
if([success boolValue] == YES){
self.countryList = [jsonObject objectForKey:@"countryList"];
dispatch_async(dispatch_get_main_queue(), ^{
[self.myTableView reloadData];
});
}
else {
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
}
//number of rows in a given section of a table view
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
NSInteger numberOfRows = 0;
//get the count from the array
if ([tableView isEqual:self.myTableView]){
numberOfRows = self.countryList.count;
}
//if user searched for something and found nothing just add a row to display a message
if(numberOfRows == 0 && [self.queryString length] > 0){
numberOfRows = 1;
}
NSLog(@"Rows: %i", numberOfRows);
return numberOfRows;
}
//asks the data source for a cell to insert in a particular location of the table view
- (UITableViewCell *) tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *myCellView = nil;
if ([tableView isEqual:self.myTableView]){
static NSString *TableViewCellIdentifier = @"CountryCells";
//create a reusable table-view cell object located by its identifier
myCellView = [tableView dequeueReusableCellWithIdentifier:TableViewCellIdentifier];
if (myCellView == nil){
myCellView = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:TableViewCellIdentifier];
}
//if there are countries to display
if(self.countryList.count > 0){
NSDictionary *countryInfo = [self.countryList objectAtIndex:indexPath.row];
NSLog(@"Country Info = %@",countryInfo);
NSString *countryCode = [countryInfo valueForKey:@"code"];
NSString *countryName = [countryInfo valueForKey:@"name"];
myCellView.textLabel.text = [NSString stringWithFormat:@"%@",countryName];
myCellView.detailTextLabel.text = countryCode;
}
//display message to user
else {
myCellView.textLabel.text = @"No Results found, try again!";
myCellView.detailTextLabel.text = @"";
}
//set the table view cell style
[myCellView setSelectionStyle:UITableViewCellSelectionStyleNone];
}
return myCellView;
}
//user tapped on the cancel button
- (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar {
NSLog(@"User canceled search");
[searchBar resignFirstResponder];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Reference
1 comment:
Thanks for sharing this informative blog.This is one of the best resources I have found in quite some time. Nicely written and great info. I really cannot thank you enough for sharing.I’ve been commenting a lot on a few blogs recently, but I hadn’t thought about my approach until you brought it up.
Post a Comment
NO JUNK, Please try to keep this clean and related to the topic at hand.
Comments are for users to ask questions, collaborate or improve on existing.