ios UITableView表格实现搜索栏搜索

NSDictionary-DeepMutableCopy.h:

#import <Foundation/Foundation.h>

@interface NSDictionary(DeepMutableCopy)

-(NSMutableDictionary *)mutableDeepCopy;

@end

类别DeepMutableCopy为NSDictionary实现新的方法,实现对NSDictionary的深层拷贝,

如果只是用NSMutableDictionary, 则此对象和源对象将会指向同一个对象,对copy对象修改的话,也会同时修改源对象。

NSDictionary-DeepMutableCopy.m:

#import "NSDictionary-DeepMutableCopy.h"

@implementation NSDictionary(DeepMutableCopy)

-(NSMutableDictionary *)mutableDeepCopy

{

    NSMutableDictionary *ret = [[NSMutableDictionary allocinitWithCapacity:[self count]]; //预分配了一个self count大的空间来存储

    NSArray *keys = [self allKeys];

    for (id key in keys)                //快速枚举,循环所有keys

    {

        id oneValue = [self valueForKey:key];  //设置oneValue为源值

        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];

        [ret setValue:oneCopy forKey:key];

    }

    return ret;

}

@end

创建了一个对NSDictionary对象的深层拷贝。如果对象没有相应mutableDeepCopy,那么它将尝试创建可变副本。

如果对象也没有相应mutableCopy消息,则按照常规方式创建副本。以确保对字典中包含的所有对象都创建了副本。

原来不是所有的对象都支持 copy只有遵守NSCopying 协议的类才可以发送copy消息

只有遵守NSMutableCopying 协议的类才可以发送mutableCopy消息
假如发送了一个没有遵守上诉两协议而发送 copy或者 mutableCopy,那么就会发生异常
默认 nsobject没有遵守这两个协议
但是 copy和mutableCopy这两个方法是nsobject定义的
如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法
如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法
看了一下几个遵守 NSCopying协议的基本上是一些基础核心类
比如 NSString NSNumber
copy以后,就是返回一个新的类,你要负责释放掉,原先被拷贝的retaincount没有+1 所以,不需要负责释放
copy和mutableCopy 就是copy返回后的是不能修改的对象, mutableCopy返回后是可以修改的对象

SectionsViewController.h:

#import <UIKit/UIKit.h>

@interface SectionsViewController : UIViewController

<UITableViewDataSourceUITableViewDelegate>

{

    UITableView *table;

    UISearchBar *search;

    NSDictionary *allNames;

    NSMutableDictionary *names;

    NSMutableArray  *keys;    

    BOOL    isSearching;

}

@property (nonatomicretainIBOutlet UITableView *table;

@property (nonatomicretainIBOutlet UISearchBar *search;

@property (nonatomicretainNSDictionary *allNames;

@property (nonatomicretainNSMutableDictionary *names;

@property (nonatomicretainNSMutableArray *keys;

- (void)resetSearch;

- (void)handleSearchForTerm:(NSString *)searchTerm;

@end

SectionsViewController.m:

#import "SectionsViewController.h"

#import "NSDictionary-DeepMutableCopy.h"

@implementation SectionsViewController

@synthesize table;

@synthesize search;

@synthesize allNames;

@synthesize names;

@synthesize keys;

#pragma mark -

#pragma mark Custom Methods

- (void)resetSearch {

    NSMutableDictionary *allNamesCopy = [self.allNames mutableDeepCopy];//字典对象进行深层拷贝

    self.names = allNamesCopy;

    [allNamesCopy release];

    [keyArray addObject:UITableViewIndexSearch];//放大镜

    NSMutableArray *keyArray = [[NSMutableArray allocinit];

    [keyArray addObjectsFromArray:[[self.allNames allKeys

                                   sortedArrayUsingSelector:@selector(compare:)]];//按字幕顺序进行排序后,将字典对象中所有的键存入可变数组

    self.keys = keyArray;

    [keyArray release];

}

取消搜索或者更改搜索条件时调用此方法。它所作的就是创建allnames的可变副本。返回的names和keys都是可变的!

- (void)handleSearchForTerm:(NSString *)searchTerm

{

    NSMutableArray *sectionsToRemove = [[NSMutableArray allocinit];//准备删除的区块

    [self resetSearch];

    

    for (NSString *key in self.keys) {//遍历可变数组keys

        NSMutableArray *array = [names valueForKey:key];//将所有keys中的key存入array

        NSMutableArray *toRemove = [[NSMutableArray allocinit];

        for (NSString *name in array) {//遍历装有所有key的数组

            if ([name rangeOfString:searchTerm 

                            options:NSCaseInsensitiveSearch].location == NSNotFound)

                [toRemove addObject:name];

        }//如果输入的在array中没有找到,则将该条记录存入待删除数组

        

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

            [sectionsToRemove addObject:key];

        //如果某一区块内所有的要删除数据的长度等于区块内所有数据的长度,

        //证明搜索的内容不在该区块中,则这个区块为空,存入待删除区块中

        [array removeObjectsInArray:toRemove];//删除待删除数组

        [toRemove release];

    }

    [self.keys removeObjectsInArray:sectionsToRemove];//删除待删除区块

    [sectionsToRemove release];

    [table reloadData];//重新加载table

}

- (void)viewDidLoad {

    NSString *path = [[NSBundle mainBundlepathForResource:@"sortednames"

                                                     ofType:@"plist"];//获取文件路径

    NSDictionary *dict = [[NSDictionary alloc

                          initWithContentsOfFile:path];//从文件中加载数据

    self.allNames = dict;

    [dict release];

    

    [self resetSearch];

    [table reloadData];

    [table setContentOffset:CGPointMake(0.044.0animated:NO];//设置偏移值为44像素,即搜索栏高度。

}

- (void)viewDidUnload {

// Release any retained subviews of the main view.

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

    self.names = nil;

    self.keys = nil;

    self.table = nil;

    self.search = nil;

    self.allNames = nil;

}

- (void)dealloc {

    [names release];

    [keys release];

    [table release];

    [search release];

    [allNames release];

    [super dealloc];

}

#pragma mark -

#pragma mark Table View Data Source Methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

{

    return [keys count];

}//区块的数量是由数组内数据的数量决定的,即keys数组中有多少值(A、B、C...)

- (NSInteger)tableView:(UITableView *)tableView 

 numberOfRowsInSection:(NSInteger)section

{

    if ([keys count] == 0)

        return 0;

    

    NSString *key = [keys objectAtIndex:section]; //被选取的某一个区块的值,比如A区块值即为A

    NSArray *nameSection = [names objectForKey:key];//在数据字典中键为A的数组的数量,即为A区块中行数

    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 = @"SectionsTableIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:

                             SectionsTableIdentifier ];

    if (cell == nil) {

        cell = [[[UITableViewCell allocinitWithStyle:UITableViewCellStyleDefault 

                                       reuseIdentifier: SectionsTableIdentifier ] autorelease];

    }

    

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

    return cell;

}//构建每一行的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;

}//设置每一个区块的标题,该区块所有数据的键均为A,则标题为A

- (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];

    search.text = @"";

    isSearching = NO;

    [tableView reloadData];

    return indexPath;

}//如果用户在食用搜索栏时单击一行,则关闭键盘

- (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;

}//如果用户点击放大镜,则返回NSNotFound,表视图收到此相应,就知道需要滚至顶部,取消了偏移!

#pragma mark -

#pragma mark Search Bar Delegate Methods

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar

{

    NSString *searchTerm = [searchBar text];

    [self handleSearchForTerm:searchTerm];

}//搜索方法

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar

{

    isSearching = YES;

    [table reloadData];

}

- (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];

}

@end

原文地址:https://www.cnblogs.com/hopeanCom/p/2789566.html