Sections(4)~検索バーの追加(2)

2010. 11. 24
●ビューコントローラのソースファイルの編集

SectionsViewController.mを開き、

1)カテゴリNSDictionary-MutableDeepCopyのインポート
2)プロパティの実装
3)検索用メソッド2つの実装
4)viewDidLoadメソッドの修正
5)viewDidUnloadとdeallocへのプロパティの追加
6)テーブルビューデータソースメソッドの修正
7)テーブルビューデリゲートメソッドの追加
8)検索バーデリゲートメソッドの追加

以上の追加・修正を行います。
(太字が追加・修正した部分)

#import "SectionsViewController.h"
#import "NSDictionary-MutableDeepCopy.h"

@implementation SectionsViewController

@synthesize table;
@synthesize search;
@synthesize allNames;

@synthesize names;
@synthesize keys;

#pragma mark -
#pragma mark Custom Methods

- (void)resetSearch {
    self.names = [self.allNames mutableDeepCopy];
    NSMutableArray *keyArray = [[NSMutableArray alloc] init];
    [keyArray addObjectsFromArray:[[self.allNames allKeys] sortedArrayUsingSelector:@selector(compare:)]];
    self.keys = keyArray;
    [keyArray release];
}

- (void)handleSearchForTerm:(NSString *)searchTerm {
    NSMutableArray *sectionsToRemove = [[NSMutableArray alloc] init];
    [self resetSearch];
    for (NSString *key in self.keys) {
        NSMutableArray *array = [names valueForKey:key];
        NSMutableArray *toRemove = [[NSMutableArray alloc] init];
        for (NSString *name in array) {
            if ([name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location == NSNotFound)
                [toRemove addObject:name];
        }
        if ([array count] == [toRemove count])
            [sectionsToRemove addObject:key];
        [array removeObjectsInArray:toRemove];
        [toRemove release];
    }
    [self.keys removeObjectsInArray:sectionsToRemove];
    [sectionsToRemove release];
    [table reloadData];
}
 

#pragma mark -
#pragma mark UIViewController Methods

(中略)

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *path = [[NSBundle mainBundle] pathForResource:@"sortednames" ofType:@"plist"];
    NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
    self.allNames = dict;
    [dict release];
    [self resetSearch];
    search.autocapitalizationType = UITextAutocapitalizationTypeNone;
    search.autocorrectionType = UITextAutocorrectionTypeNo;

}

(中略)

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;

    self.table = nil;
    self.search = nil;
    self.allNames = nil;

    self.names = nil;
    self.keys = nil;
    [super viewDidUnload];
}

- (void)dealloc {
    [table release];
    [search release];
    [allNames release];

    [names release];
    [keys release];
    [super dealloc];
}

#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 = @"SectionsTableIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SectionsTableIdentifier] autorelease];
    }
    cell.textLabel.text = [nameSection objectAtIndex:row];
    return cell;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if ([keys count] == 0)
        return @"";


    NSString *key = [keys objectAtIndex:section];
    return key;
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return keys;
}

#pragma mark -
#pragma mark Table View Delegate Methods

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [search resignFirstResponder];
    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 {
    search.text = @"";
    [self resetSearch];
    [table reloadData];
    [searchBar resignFirstResponder];
}
 

@end

947_



1)カテゴリNSDictionary-MutableDeepCopyのインポート

可変辞書生成メソッドmutableDeepCopyを使用するため、NSDictionary-MutableDeepCopy.hをインポートします。


2)プロパティの実装

アウトレットであるテーブルビューのtableと検索バーのsearch、元となる不変辞書のallNames、(同名なので追加ではありませんが)可変辞書のnamesとキーkeysのプロパティを実装します。


3)検索用メソッド2つの実装

resetSearch

resetSearchメソッドは、検索をキャンセルした時などにテーブルビュー表示用の可変辞書をリセットするメソッドです。

・allNames:元になる不変辞書
・names:検索結果を反映させた可変辞書
・keys:検索結果を反映させた可変配列

メソッド内で一時的に使う変数)
・keyArray:不変辞書内のキーをソートした可変配列

可変辞書namesは、元となる不変辞書allNamesからカテゴリメソッドmutableDeepCopyで可変コピーを生成します。

可変配列keysは、一時的な可変配列keyArrayを用意して、不変辞書allNamesからallKeysメソッドで全てのキーを取得し、sortedArrayUsingSelector:メソッドで昇順で並べ替え、addObjectsFromArray:で追加したものを入れています。

handleSearchForTerm:

handleSearchForTerm:メソッドは、検索バーに入力された語句を元に可変辞書namesとそのキー配列keysを組み替えるもので、検索バーのデリゲートメソッドであるsearchBarSearchButtonClicked:searchBar:textDidChange:から呼び出されます。
(両メソッドについては後述します)

・keys:検索結果を反映させた可変配列
・names:検索結果を反映させた可変辞書
・searchTerm:メソッドの引数で、検索バーに入力された語句
・table:アウトレットのテーブルビュー

メソッド内で一時的に使う変数)
・key:可変配列keysの要素で値の取得に用いるキー文字列
・array:可変辞書からkeyで取得される値の可変配列
・name:array内にある値の文字列
・toRemove:検索語句が含まれていない値を入れる一時保管庫
・sectionsToRemove:検索語句が含まれていないセクションのキーを入れる一時保管庫

ここでは検索語句を元に、該当しない値やセクションのキーを削除して、検索結果を反映させたデータを生成します。

各キーと値を総当たりするため、キーの高速列挙内に値の高速列挙が組み込んであります。

最初にresetSearchメソッドを呼び出し、可変辞書namesとそのキー配列keysを初期化します。

次にキーを取得する高速列挙のループに入り、キー文字列keyを使って辞書namesからvalueForKey:で値の配列arrayを取り出します。

得られた配列arrayを使って値nameを取得する高速列挙のループに入り、値の中に検索語句searchTermが含まれているかどうかをrangeOfString:options:で検索します。
(オプションのNSCaseInsensitiveSearchは、大文字/小文字を区別しない検索です)

rangeOfString:options:は第一引数で指定した文字列が含まれている場合の範囲をNSRangeで返します。

locationはNSRange構造体のメンバ変数で範囲の開始位置を示すもので、ここでのドット演算子はプロパティへのアクセスではありません。

locationがNSNotFound、つまり検索語句が見つからなかった場合、削除対象の値を一時保管するtoRemove配列にその値nameをaddObjectで追加します。

そのキー内の全ての値をチェックし終えたら、キー内の値arrayの要素数と削除対象を保管したtoRemoveの要素数を比較し、キー内に該当する値が無い場合はそのkeyを削除対象としてsectionsToRemoveにaddObjectで追加します。

削除対象の値toRemoveは、値の配列arrayからremoveObjectsInArray:で削除します。

全てのキーの検索が終わったら、削除対象のキーsectionsToRemoveはキーの配列keysからremoveObjectsInArray:で削除します。

不要なキーと値の削除が済んだら、最後にreloadDataでテーブルビューを再読み込みします。


addObjectsFromArray:

- (void)addObjectsFromArray:(NSArray *)otherArray

レシーバの内容の末尾に、指定した他の配列のオブジェクトを追加します。

otherArray:レシーバの内容の末尾に追加する配列オブジェクトを指定します。


searchBarSearchButtonClicked:

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar

検索ボタンがタップされたことをデリゲートメソッドに伝えます。

検索を開始するにはこのメソッドを実装する必要があります。

検索バーのテキストの取得にはtextプロパティを使用します。

プログラムによる編集を開始するため、検索バーにbecomeFirstResponderを送信することもできます。

searchBar:タップされる検索バーを指定します。


searchBar:textDidChange

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText

ユーザが検索テキストを変更したことをデリゲートに伝えます。

このメソッドは検索テキストフィールドからテキストがクリアされた時に呼び出されます。

searchBar:編集されている検索バーを指定します。

searchText:検索テキストフィールド内の現在のテキストです。


addObject:

- (void)addObject:(id)anObject

レシーバの最後に指定したオブジェクトを挿入します。

重要:anObjectがnilの場合、NSInvalidArgumentExceptionが発生します。

anObject:レシーバの内容の最後に追加するオブジェクトを指定します。
この値をnilにしてはいけません。


removeObjectsInArray:

- (void)removeObjectsInArray:(NSArray *)otherArray

指定した別の配列内のオブジェクトを、レシーバの配列から削除します。

このメソッドはremoveObject:に似ていますが、一回の処理でオブジェクト内の大きなセットを効率的に削除することができます。

otherArray内のオブジェクトがレシーバの配列に含まれていない場合、このメソッドは何の効果も与えません。
(ただし、コンテンツを検索するオーバーヘッドは生じます)

このメソッドは、otherArray内の全ての要素がhashとisEqual:に応答することを前提にしています。

otherArray:レシーバの配列から削除するためのオブジェクトを含む配列を指定します。


reloadData

- (void)reloadData

レシーバのセクションと行を再読み込みします。

このメソッドは、セルを含むセクションのヘッダとフッタ、インデックス配列など、テーブルの構成に使用する全てのデータを再読み込みします。

効率化のため、テーブルビューは可視状態の行のみ再表示します。

再読み込みの結果、テーブルが小さくなった場合はオフセットを調整します。

テーブルビューの完全なデータの再読み込みをしたい時は、このメソッドでテーブルビューのデリゲートまたはデータソースを呼び出します。

このメソッド内で、行の挿入や削除、特にbeginUpdatesendUpdatesの呼び出しを伴うアニメーションブロックの実装は行わないでください。


4)viewDidLoadメソッドの修正

以前はプロパティリストsortednames.plistから辞書namesと配列keysを生成していましたが、namesが検索結果用の可変辞書の名前になったので固定辞書はallNamesとなり、keysは可変配列としてresetSearchメソッドで定義され、呼び出すことになっています。

それと検索バーの属性の設定が2つ追加されています。

autocapitalizationTypeはテキストフィールドに入力された文字を自動で大文字にするかどうかを決めるプロパティで、デフォルト値のUITextAutocapitalizationTypeNoneと明示し、大文字にはしないことになっています。

autocorrectionTypeはテキストフィールドに入力された文字に対する自動校正の有効/無効を決めるプロパティで、こちらはデフォルト値ではなくUITextAutocorrectionTypeNoと自動校正を無効にしています。


5)viewDidUnloadとdeallocへのプロパティの追加

追加したプロパティ(table、search、allNames)について、viewDidUnloadでの所有権の放棄とdeallocでの解放を追加しています。


6)テーブルビューデータソースメソッドの修正

テーブルビューのデータソースメソッドの内3つに修正が加えられており、検索の結果でセクションや行が0の場合の対処の追加がされています。

numberOfSectionsInTableView:

テーブルビューのセクション数を返すメソッドでは、以前はキー配列の要素数をそのまま返していましたが、検索した結果キーの要素数(セクション数)が0になる可能性があるため、0より上ならkeysの要素数をそのまま返し、0なら1を返すようにしています。

tableView:numberOfRowsInSection:

テーブルビューの指定したセクションの行数を返すメソッドでは、有効なセクションが存在しない場合には0を返す判定文が、行数カウントの処理の前に追加されています。

tableView:titleForHeaderInSection:

テーブルビューのセクションのタイトルを返すメソッドでは、有効なセクションが存在しない場合にはタイトル文字列を空にする判定分が、タイトル文字列の処理の前に追加されています。


7)テーブルビューデリゲートメソッドの追加

テーブルビューのデリゲートメソッドで追加されているtableView:willSelectRowAtIndexPath:は、行が選択される時に呼び出されるメソッドで、ここでは検索バーに対する処理を行っています。

検索バーがアクティブの状態だと画面下半分にキーボードが出たままになるので、テーブルビューの行をタップしたらキーボードが消えるよう、resignFirstResponderメソッドで検索バーがFirst Responderを放棄するようにしています。


8)検索バーデリゲートメソッドの追加

最後に検索バーのデリゲートメソッドが3つ追加されています。

searchBarSearchButtonClicked:

キーボード右下にある『Search』ボタンがタップされた時の処理で、検索バーに入力されている語句をtextプロパティで取得し、検索処理メソッドhandleSearchForTerm:に渡しています。

searchBar:textDidChange:

検索バーのテキストフィールド内の語句が変更された時に呼び出されるメソッドです。

テキストフィールド内の語句が空(length == 0)になった場合は、resetSearchメソッドで可変辞書を元の辞書で初期化し直し、reloadDataでテーブルビューの再読み込みをしています。

検索語句がある場合、その語句を引数として検索処理メソッドhandleSearchForTerm:に渡しています。

searchBarCancelButtonClicked:

検索バーの右端にある『Cancel』ボタンがタップされた時の処理で、検索語句をtextプロパティで空にし、resetSearchメソッドで可変辞書を元の辞書で初期化し直し、reloadDataでテーブルビューの再読み込みした後、resignFirstResponderメソッドで検索バーがFirst Responderを放棄するようにしています。


searchBarSearchButtonClicked:

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar

検索ボタンがタップされたことをデリゲートメソッドに伝えます。

検索を開始するにはこのメソッドを実装する必要があります。

検索バーのテキストの取得にはtextプロパティを使用します。

プログラムによる編集を開始するため、検索バーにbecomeFirstResponderを送信することもできます。

searchBar:タップされる検索バーを指定します。


text

@property(nonatomic, copy) NSString *text

現在の、または開始時の検索テキストです。

デフォルト値はnilです。


searchBar:textDidChange

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText

ユーザが検索テキストを変更したことをデリゲートに伝えます。

このメソッドは検索テキストフィールドからテキストがクリアされた時に呼び出されます。

searchBar:編集されている検索バーを指定します。

searchText:検索テキストフィールド内の現在のテキストです。


searchBarCancelButtonClicked:

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar

キャンセルボタンがタップされたことをデリゲートに伝えます。

通常、検索バーを閉じるためにこのメソッドを実装します。

searchBar:タップされる検索バーを指定します。



参考文献

UISearchBarDelegate Protocol Reference

NSMutableArray Class Reference

UITableView Class Reference

UISearchBar Class Reference

Wikipedia/条件演算子

はじめてのiPhone3プログラミングはじめてのiPhone3プログラミング
(2009/12/17)
Dave Mark、Jeff LaMarche 他

商品詳細を見る






Wave SoundTouch music system IV
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
06 | 2017/07 | 08
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

Wave SoundTouch music system IV
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR