2011年9月17日 星期六

Lala's Program Note 實作記錄: 20. search criteria

since: 2011/09/15
update: 2011/12/02


參考資料:
1. iPhone Development – core data search criteria tutorial
2. iPhone Development – core data search criteria tutorial part 2

A. 之前, 在 Lala's Program Note 實作記錄: 2.標籤列架構, 中的 G. 增加 Search(搜尋)
    頁籤, 已新增了 SearchViewController, 現在開始手動加入 UI 元件:
    1. 修改 SearchViewController.h 檔案如下:
#import <UIKit/UIKit.h>
//@add
#import <CoreData/CoreData.h>

@interface SearchViewController : UIViewController {
    //@add
    UISearchBar         *mySearchBar;
    UISegmentedControl  *mySegmentedControl;
    UITableView         *myTableView;
}

//@add
@property (nonatomic, retain) UISearchBar         *mySearchBar;
@property (nonatomic, retain) UISegmentedControl  *mySegmentedControl;
@property (nonatomic, retain) UITableView         *myTableView;

@end

----------------------------------------------------------------------------------------------------------

    2. 修改 SearchViewController.m 檔案如下:
@synthesize mySearchBar, mySegmentedControl, myTableView;

//@add
- (void)dealloc
{
    [mySearchBar release];
    [mySegmentedControl release];
    [myTableView release];

    [super dealloc];
}

#pragma mark - View lifecycle
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    //@add   
    // screen resolution: iPhone 320x480 ; iPhone4 640x960
    /* mySearchBar */
    mySearchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,0,320,40)];
    [self.view addSubview:mySearchBar];
    [mySearchBar release];
   
    /* mySegmentedControl */
    mySegmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"All", @"Title", @"Content", nil]];

    [mySegmentedControl setFrame:CGRectMake(5,45,310,35)];
    mySegmentedControl.selectedSegmentIndex = 0;
    [self.view addSubview:mySegmentedControl];
    [mySegmentedControl release];
   
    /* myTableView */
    myTableView = [[UITableView alloc] init];
    [myTableView setFrame:CGRectMake(0,85,320,400)];
    [self.view addSubview:myTableView];
    [myTableView release]; 
}

----------------------------------------------------------------------------------------------------------

    3. 完成的 UI 如下所示:

B. 建立用來表現 managed object 的客製物件:
   1. Select NoteBook entity in the model editor.
      > File > New > New File > Core Data > NSManagedObject subclass >
        Next

     說明: 產生 NoteBook.h 與 NoteBook.m 檔案

   2. Select NoteArticle entity in the model editor.
      > File > New > New File > Core Data > NSManagedObject subclass >
        Next

     說明: 產生 NoteArticle.h 與 NoteArticle.m 檔案


C. 增加相關的 protocolsearch 的處理
   1. 修改 SearchViewController.h 檔案如下:
//@interface SearchViewController : UIViewController {
@interface SearchViewController : UIViewController <UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource> {
    //@add
    UISearchBar         *mySearchBar;
    UISegmentedControl  *mySegmentedControl;
    UITableView         *myTableView;

    //@add
    NSFetchedResultsController  *fetchedResultsController;
    NSManagedObjectContext      *managedObjectContext;
   
    //@add
    NSMutableString *searchCriteria; // to hold search criteria
    NSArray *fetchedObjects;         // to hold search results
}

//@add
@property (nonatomic, retain) UISearchBar         *mySearchBar;
@property (nonatomic, retain) UISegmentedControl  *mySegmentedControl;
@property (nonatomic, retain) UITableView         *myTableView;

//@add
@property (nonatomic, retain) NSFetchedResultsController    *fetchedResultsController;
@property (nonatomic, retain) NSManagedObjectContext        *managedObjectContext;

//@add
- (IBAction)segmentedControlChanged;
// We have conform UISearchBarDelegate protocol, so it will auto triger this method
- (void)searchBarSearchButtonClicked:(UISearchBar *)theSearchBar;

@end

----------------------------------------------------------------------------------------------------------

   2. 修改 SearchViewController.m 檔案如下:
#import "SearchViewController.h"
//@add
#import "NoteBook.h"
#import "NoteArticle.h"
//add
#import "ArticleViewController.h"

@implementation SearchViewController
//@add
@synthesize mySearchBar, mySegmentedControl, myTableView;
@synthesize managedObjectContext, fetchedResultsController;


//@add
- (void)dealloc
{
    [mySearchBar release];
    [mySegmentedControl release];
    [myTableView release];
   
    //@update
    [managedObjectContext release];
    [fetchedResultsController release];
    [searchCriteria release];

    [super dealloc];
}

//@add
- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar
{
    NSLog(@"searchBarSearchButtonClicked with searchCriteria = %@", searchCriteria);
   
    NSError *error = nil;
   
    // We use an NSPredicate combined with the fetchedResultsController to perform the search
    // * the [cd] bit specifies a case & diacritic insensitive search (不分大小寫)
    if (self.mySearchBar.text !=nil)
    {
        // search for all article (both title & content)
        if ([searchCriteria isEqualToString:@"all"])
        {  
            NSPredicate *predicate =[NSPredicate predicateWithFormat:@"title contains[cd] %@ OR content contains[cd] %@", self.mySearchBar.text, self.mySearchBar.text];

            [fetchedResultsController.fetchRequest setPredicate:predicate];
        }
        // search for article's title
        else if ([searchCriteria isEqualToString:@"title"])
        {
            NSPredicate *predicate =[NSPredicate predicateWithFormat:@"title contains[cd] %@", self.mySearchBar.text];

            [fetchedResultsController.fetchRequest setPredicate:predicate];
        }
        // search for article's content
        else if ([searchCriteria isEqualToString:@"content"])
        {
            NSPredicate *predicate =[NSPredicate predicateWithFormat:@"content contains[cd] %@", self.mySearchBar.text];

            [fetchedResultsController.fetchRequest setPredicate:predicate];
        }
    }
    else
    {
        NSPredicate *predicate =[NSPredicate predicateWithFormat:@"All"];
        [fetchedResultsController.fetchRequest setPredicate:predicate];
    }
   
    if (![[self fetchedResultsController] performFetch:&error])
    {
        // Handle error
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
   
    // this array is just used to tell the table view how many rows to show
    fetchedObjects = fetchedResultsController.fetchedObjects;
   
    // dismiss the search keyboard
    [mySearchBar resignFirstResponder];
   
    // reload the table view
    [myTableView reloadData];
}


//@add
- (IBAction)segmentedControlChanged
{
    switch (mySegmentedControl.selectedSegmentIndex)
    {
        case 0:
            [searchCriteria setString:@"all"];
            return;
        case 1:
            [searchCriteria setString:@"title"];
            return;
        case 2:
            [searchCriteria setString:@"content"];
            return;
    }
}


#pragma mark - View lifecycle
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    //@add   
    // screen resolution: iPhone 320x480 ; iPhone4 640x960
    /* mySearchBar */
    mySearchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,0,320,40)];
    //@add
    mySearchBar.delegate = self;
    //mySearchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [self.view addSubview:mySearchBar];
    [mySearchBar release];
   
   
    /* mySegmentedControl */
    mySegmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"All", @"Title", @"Content", nil]];
    [mySegmentedControl setFrame:CGRectMake(5,45,310,35)];
    mySegmentedControl.selectedSegmentIndex = 0;
    //@add
    [mySegmentedControl addTarget:self action:@selector(segmentedControlChanged) forControlEvents:UIControlEventValueChanged];

    [self.view addSubview:mySegmentedControl];
    [mySegmentedControl release];
   
   
    /* myTableView */
    myTableView = [[UITableView alloc] init];
    [myTableView setFrame:CGRectMake(0,85,320,400)];
    //@add
    myTableView.delegate = self;
    myTableView.dataSource = self;
   
    [self.view addSubview:myTableView];
    [myTableView release];   
   
   
    //@add
    //initializing our searchCriteria NSString
    searchCriteria = [[NSMutableString alloc] initWithString:@"title"];
   
    // NSFetchRequest needed by the fetchedResultsController
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
   
    // NSSortDescriptor tells defines how to sort the fetched results
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
   
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
   
    [fetchRequest setSortDescriptors:sortDescriptors];
   
    // fetchRequest needs to know what entity to fetch
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"NoteArticle" inManagedObjectContext:managedObjectContext];
   
    [fetchRequest setFetchBatchSize:10];
    [fetchRequest setEntity:entity];
    [sortDescriptor release];
    [sortDescriptors release];
   
    fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"SearchArticles"];
   
    [fetchRequest release];
}


#pragma mark Table view Methods
#pragma mark Table view data source
//@add
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [[self.fetchedResultsController sections] count]; //return 1;
}

//@add
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    //id<NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    //return [sectionInfo numberOfObjects];
    return [fetchedObjects count];
}

//@add
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *MyIdentifier = @"SearchCell";
   
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
   
    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:MyIdentifier] autorelease];
    }
   
    // customize cell
    NoteArticle *noteArticle = [self.fetchedResultsController objectAtIndexPath:indexPath];
   
    NSMutableString *cellTitle = [[[NSMutableString alloc] init] autorelease];
    [cellTitle appendString:noteArticle.title];
    cell.textLabel.text = cellTitle;
    cell.textLabel.textColor = [UIColor brownColor];

   
    NSMutableString *cellSubTitle = [[[NSMutableString alloc] init] autorelease];
    [cellSubTitle appendString:noteArticle.subTitle];
    cell.detailTextLabel.text = cellSubTitle;
    cell.detailTextLabel.textColor = [UIColor darkGrayColor];

   
    return cell;
}


//@add
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    ArticleViewController *articleViewController = [[ArticleViewController alloc] init];
   
    NSManagedObject *article = [self.fetchedResultsController objectAtIndexPath:indexPath];
   
    articleViewController.article = article;

   
// relationship
    articleViewController.title = [[article valueForKey:@"notebook"] valueForKey:@"name"];

    [self.navigationController pushViewController:articleViewController animated:YES];
   
    [articleViewController release];
}

@end

----------------------------------------------------------------------------------------------------------

   3. 修改 Lala_s_Program_NoteAppDelegate.m 檔案如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ....


     /* C. for SearchViewController */
    // 1. Create a instance of SearchViewController
    SearchViewController *searchViewController = [[SearchViewController alloc] init];
   
    // 2. set controller's managed object context member right after initializing
    //@add
    searchViewController.managedObjectContext = self.managedObjectContext;
    ....
}


D. 結果:




沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。