IOS5基礎之十三-----實現搜索欄

爲什麼要把搜索欄單獨寫,主要是這裏牽涉到一個深層可變副本。在這裏爲什麼要用這個~~~~你迷茫嗎?

我也很迷茫哈哈~~~~~~

該項目是請一個項目的加強版,雖然只是多了一個搜索控件,可是卻多了許多步驟。

上次公司需要添加一個字段。也就是在數據庫中新增一個字段。我排的時間相對長了一點,受到衆人笑話。可是當你對系統的複雜性瞭解後,你會知道特別時在數據庫增加字段時帶來了很多的問題。並且我這個字段幾乎整個項目的所有表都要增加。因爲每張表的關聯性,並且有些地方要添加,有的地方使用存儲過程,有的是創建臨時表,如果要時間短,是可以完成,但是誰有知道那些地方沒有修改,當過了一段時間後,就會有一段垃圾數據出現,那時也只有去修改數據庫了,哈哈廢話一段!!!!也許還是我的能力有限。

前面我使用了多數組的字段,其中字母表中的每個字母都佔用一個數組。該字典是不可改變的。這就意味着不能從字典添加和刪除值。它包含的數組也是如此。所以要創建兩個字典,一個包含完整數據集的不可改變的字典,一個可以從中刪除行的可變的字典副本。

複習一下,淺層複製和深層複製

淺層複製:不復制引用對象,新複製的對象值指向現有的引用對象。

深層複製:將複製所用的引用對象。

NSDictionary遵循NSMutableCopying協議,該方法創建的是一個淺層副本。但是引用對象是不能刪除的,所以是無法刪除對象的。需要一個類別去存放數組的字典的副本。


添加類別後 項目導航變成


在頭文件中做一個接口返回NSMutbleDictionary類型的方法

#import <Foundation/Foundation.h>

@interface NSDictionary (MutableDeepCopy)

-(NSMutableDictionary *) mutableDeepCopy;

@end


實現改方法

- (NSMutableDictionary *)mutableDeepCopy {

    NSMutableDictionary *returnDict = [[NSMutableDictionary alloc]

                                       initWithCapacity:[self count]];

    NSArray *keys = [self allKeys];

    for (id key in keys) {

        id oneValue = [self valueForKey:key];

        id oneCopy = nil;

        

        if ([oneValue respondsToSelector:@selector(mutableDeepCopy)])

            oneCopy = [oneValue mutableDeepCopy];

        else if ([oneValue respondsToSelector:@selector(mutableCopy)])

            oneCopy = [oneValue mutableCopy];

        if (oneCopy == nil)

            oneCopy = [oneValue copy];

        [returnDict setValue:oneCopy forKey:key];

    }

    return returnDict;

}

用一個數組存儲這個這個字典。遍歷並且判斷對象如果沒有響應mutableDeepCopy消息,那麼它將創建可變副本,否則就創建常規副本。

for (id  key in keys)稱爲快速枚舉類似C#中的foreach()方法。NSDictionary 、NSArray、NSSet都支持快速枚舉。


現在頭文件修改爲

#import <UIKit/UIKit.h>


@interface BIDViewController :UIViewController

<UITableViewDataSource,UITableViewDelegate>


@property (strong,nonatomicIBOutlet UITableView *table;   //指向輸出口視圖

@property (strong,nonatomicIBOutlet UISearchBar *search;  //指向輸出口搜索欄

@property (strong,nonatomicNSDictionary *allNames;        //字典存放所有的數據集

@property (strong,nonatomicNSMutableDictionary *names;    //將存有那些與當前搜索條件匹配的數據集

@property (strong,nonatomicNSMutableArray *keys;          //將存有索引值和分區名稱

@property (assignnonatomicBOOL isSearching;             //是否在使用搜索欄

-(void)resetSearch;                                        //複製數據

-(void)handleSearchForTerm:(NSString *)searchTerm;          //實現搜索的方法


@end

實現方法如下

#import "BIDViewController.h"

#import "NSDictionary+MutableDeepCopy.h"


@implementation BIDViewController

@synthesize table;

@synthesize search;

@synthesize allNames;

@synthesize names;

@synthesize keys;

@synthesize isSearching;


#pragma mark

#pragma mark Custom Methods

-(void)resetSearch

{

    self.names =[self.allNames mutableDeepCopy];

    NSMutableArray *keyArray= [[NSMutableArray allocinit];

    [keyArray addObject:UITableViewIndexSearch];

    [keyArray addObjectsFromArray:[[self.allNames allKeyssortedArrayUsingSelector:@selector(compare:)]];

    self.keys=keyArray;

}


-(void) handleSearchForTerm:(NSString *)searchTerm

{

    NSMutableArray *sectionsToRemove=[[NSMutableArray allocinit];//創建一個數組,存放我們找到的空分區。

  

    [self resetSearch];

    for(NSString *key in self.keys)

    {

        NSMutableArray *array=[names valueForKey:key];//存放需要從names數組中刪除的值的數組

        NSMutableArray *toRemove=[[NSMutableArray alloc]init];

       

        for(NSString *name in array)

        {

            //循環使用一個字符串中子字符串位置的NSString的方法。並且返回一個NSRange結構,如果返回的包含了NSNotFound就添加到要刪除的對象數組中

            if ([name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location == NSNotFound

            {

                [toRemove addObject:name];

            }

        }

        if ([array count]==[toRemove count]) {

            [sectionsToRemove addObject:key];

        }

        [array removeObjectsInArray:toRemove];//從此分區中刪除不匹配的對稱

    }

     //刪除空分區 並告知重新加載數據

    [self.keys removeObjectsInArray:sectionsToRemove];

    //[sectionsToRemove release];

    [table reloadData];

}




- (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.

}


#pragma mark - View lifecycle


//初始化數據

- (void)viewDidLoad

{

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    NSString *path= [[NSBundle mainBundlepathForResource:@"sortednames"ofType:@"plist"];

    NSDictionary *dict = [[NSDictionary alloc]initWithContentsOfFile:path];

    self.allNames=dict;

    [self resetSearch];

    [table reloadData];

    [table setContentOffset:CGPointMake(0.0,44.0animated:NO];//設置表中內容的偏移量

    

}


- (void)viewDidUnload

{

    [super viewDidUnload];

    // Release any retained subviews of the main view.

    // e.g. self.myOutlet = nil;

    self.names=nil;

    self.keys=nil;

    self.allNames=nil;

    self.table=nil;

    self.search=nil;

}


- (void)viewWillAppear:(BOOL)animated

{

    [super viewWillAppear:animated];

}


- (void)viewDidAppear:(BOOL)animated

{

    [super viewDidAppear:animated];

}


- (void)viewWillDisappear:(BOOL)animated

{

    [super viewWillDisappear:animated];

}


- (void)viewDidDisappear:(BOOL)animated

{

    [super viewDidDisappear:animated];

}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

    // Return YES for supported orientations

    return (interfaceOrientation !=UIInterfaceOrientationPortraitUpsideDown);

}


#pragma mark

#pragma mark Table View Data Source Methods

//指定分區的數量

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

{

    return ([keys count])>0?[keys count]:1;

}


//用於計算特定分區中的行數,檢索與討論中的分區對應的數組。並從該數組中返回行的數量。

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

    if ([keys count]==0) {

        return 0;

    }

    NSString *key =[keys objectAtIndex:section];

    NSArray *nameSection=[names objectForKey:key];

    return [nameSection count];

}


-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    

    NSUInteger section=[indexPath section];

    NSUInteger row=[indexPath row];

    

    NSString *key =[keys objectAtIndex:section];

    NSArray *nameSection=[names objectForKey:key];

    

    static NSString *SectionsTableIdentifier=@"SectionsTableIdentifiler";

    UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];

    if (cell==nil) {

        cell=[[UITableViewCell allocinitWithStyle:UITableViewCellStyleDefault reuseIdentifier:SectionsTableIdentifier];

    }

    cell.textLabel.text=[nameSection objectAtIndex:row];

    return cell;

}


//爲每個分區指定一個可選的標題值,然後只返回這一組的字母就可以了

-(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

{

    if ([keys count]==0) {

        return nil;

    }

    NSString *key=[keys objectAtIndex:section];

    if (key==UITableViewIndexSearch) {

        return nil;

    }

    return  key;

}


//添加索引的方法

-(NSArray *) sectionIndexTitlesForTableView:(UITableView *)tableView

{

    if (isSearching)

        return nil;

    return keys;

}


#pragma mark -

#pragma mark Table View Delegate Methods

- (NSIndexPath *)tableView:(UITableView *)tableView

  willSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    [search resignFirstResponder];//如果用戶在使用搜索欄時單擊一行,我們希望鍵盤不再起作用。

    isSearching = NO;

    search.text = @"";

    [tableView reloadData];

    return indexPath;

}


#pragma mark -

#pragma mark Search Bar Delegate Methods

//當用戶單擊鍵盤上的返回按鈕或搜索按鈕時,調用,此方法從搜索欄獲取搜索短語。並調用搜索方法。

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {

    NSString *searchTerm = [searchBar text];

    [self handleSearchForTerm:searchTerm];

}


//實時搜索,只要搜索欄中的短語發生變化都重新搜索,這個是需要設備的高性能。

- (void)searchBar:(UISearchBar *)searchBar

    textDidChange:(NSString *)searchTerm {

    if ([searchTerm length] == 0) {

        [self resetSearch];

        [table reloadData];

        return;

    }

    [self handleSearchForTerm:searchTerm];

}


//取消按鈕的觸發的事件

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {

    isSearching = NO;

    search.text = @"";

    [self resetSearch];

    [table reloadData];

    [searchBar resignFirstResponder];

}


- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {

    isSearching = YES;

    [table reloadData];

}


- (NSInteger)tableView:(UITableView *)tableView

sectionForSectionIndexTitle:(NSString *)title

               atIndex:(NSInteger)index {

    NSString *key = [keys objectAtIndex:index];

    if (key == UITableViewIndexSearch) {

        [tableView setContentOffset:CGPointZero animated:NO];

        return NSNotFound;

    } else return index;

}


@end


提到一個搜索的放大器功能。

3個步驟:

a。向keys數組添加一個特殊值以指示我們需要一個放大鏡。

-(void)resetSearch

{

    self.names =[self.allNames mutableDeepCopy];

    NSMutableArray *keyArray= [[NSMutableArray allocinit];

    [keyArray addObject:UITableViewIndexSearch];

    [keyArray addObjectsFromArray:[[self.allNames allKeyssortedArrayUsingSelector:@selector(compare:)]];

    self.keys=keyArray;

}


b。必須阻止IOS在表格中顯示該特殊值的部分標題。

-(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

{

    if ([keys count]==0) {

        return nil;

    }

    NSString *key=[keys objectAtIndex:section];

    if (key==UITableViewIndexSearch) {

        return nil;

    }

    return  key;

}

c。告訴表格在該項被選中時滾至頂部。

- (NSInteger)tableView:(UITableView *)tableView

sectionForSectionIndexTitle:(NSString *)title

               atIndex:(NSInteger)index {

    NSString *key = [keys objectAtIndex:index];

    if (key == UITableViewIndexSearch) {

        [tableView setContentOffset:CGPointZero animated:NO];

        return NSNotFound;

    } else return index;

}


遇到很多問題。

1。在視圖頁面的時候,沒有在UIView中添加一個View,直接將Search Bar 拖進去。無法修改其長度。

2。 self.names =[self.allNames mutableDeepCopy];的時候mutableCopy,報數組不能變成可變的。

3。說error code。反覆驗證對比沒有發現錯誤,後來網上一查,說要重啓電腦錯誤自動消失,抓狂,搞的我花費了很長的事件認真核對代碼。

其實代碼是出來了,還是有很多地方不是很理解。要抄出來還是挺費勁的,估計是自己比較弱,哈哈。雖然花了2~3天的時間。這裏還是要重複多看看。
發佈了102 篇原創文章 · 獲贊 35 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章