cancel button on search bar does not cancel correctly - objective-c

I have a search bar, i can search now, but when I enter a text to search, and click the cancel button. It does not give me back my first stage, meaning full of the items in the table.
For example: I search the item with word: a, it gives me all the a items, yes, it is right now, but when i hit the cancel button, i want the programme gives me all the items exist, not just a items.
Here is the code: please help me out. Thank you so much.
- (void)searchBarCancelButtonClicked:(UISearchBar *)aSearchBar
{
searchBar.text = #"";
[searchBar resignFirstResponder];
letUserSelectRow = YES;
searching = NO;
self.tableView.scrollEnabled = YES;
NSLog(#"what text after cancel now: %#", searchBar.text);
[self.tableView reloadData];
}
- (NSMutableArray *) searchTableView {
NSString *searchText = searchBar.text;
NSLog(#"search text: %#", searchText);
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSMutableArray *tempArr = [[NSMutableArray alloc] init];
for (NSDictionary *dTemp in arrayData)
{
NSString *tempStr = [dTemp objectForKey:#"url"];
NSLog(#"sTemp string: %#",[ NSString stringWithFormat:#"%#", tempStr]);
NSRange titleResultsRange = [tempStr rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
{
NSLog(#"1 count :%d", [resultArray count]);
[resultArray addObject:dTemp];
NSLog(#"2 count :%d", [resultArray count]);
[tempArr addObject:resultArray];
[resultArray release];
resultArray = [NSMutableArray new];
}
}
if (resultArray != nil) {
[resultArray release];
}
return tempArr;
}
- (void)searchBar:(UISearchBar *)aSearchBar textDidChange:(NSString *)searchText
{
NSLog(#"what text after cancel now: %#", searchBar.text);
if([searchText length] > 0) {
[sortedArray removeAllObjects];
searching = YES;
letUserSelectRow = YES;
self.tableView.scrollEnabled = YES;
NSMutableArray *searchArray = [self searchTableView];
sortedArray = [[NSMutableArray alloc] initWithArray:searchArray copyItems:YES];
for (int i = 0; i<[sortedArray count]; i++) {
NSLog(#"this is the search array: %#", [[sortedArray objectAtIndex:i] class]);
}
NSLog(#"sorted array: %d", [sortedArray count]);
}
else {
searching = NO;
letUserSelectRow = NO;
self.tableView.scrollEnabled = NO;
}
[self.tableView reloadData];
}

You don't need to override any of UISearchBar methods to accomplish this. The new way of doing this relies on the UISearchDisplay controller instead (specifically on shouldReloadTableForSearchString).
Declare your view controller to conform to UISearchDisplayDelegate protocol, and keep two instance variables: your model as NSArray (all data) and a filtered array as NSMutableArray (a subset of your data). The code you presently have in "searchTableView" would filter the content of the model and place it into the filtered NSMutableArray. Then you would override the following UITableView methods: -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath. In each, before returning, make a comparison to determine whether your tableView argument is equal to self.searchDisplayController.searchResultsTableView. If it is, the user is looking at the filtered list and your should use the content of the filtered NSMutableArray to create the view, otherwise, the user is looking at the whole data set and you should use the content of the NSArray that holds your model. Take a look at the following Apple code for a simple example of what I described:
http://developer.apple.com/library/ios/#samplecode/TableSearch/Introduction/Intro.html

Related

NSSearch Field Predicate Filter

-(void) searchFieldChanged{
MPVTModelList *list = [[MPVTModelList alloc] initWithClass:[MassPOAssignmentModel class]];
[intersectionTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
// [searchIntersectionField setStringValue:[[[searchIntersectionField stringValue] stringByReplacingOccurrencesOfString:#"\\" withString:kMPVTBlankString] stringByReplacingOccurrencesOfString:#"\'" withString:kMPVTBlankString]];
[searchIntersectionField setStringValue:[searchIntersectionField stringValue]];
NSArray *array=[[NSArray alloc]init];
if([[[searchIntersectionField cell]placeholderString] isEqualToString:#"Pricing Org"]){
NSArray *tempArray=[[[searchIntersectionField stringValue] uppercaseString] componentsSeparatedByString:#","];
NSLog(#"tempArray %#",tempArray);
NSString * str=[[searchIntersectionField stringValue] uppercaseString];
NSLog(#"str is %#",str);
for(id item in tempArray ){
[intersectionTableView reloadData];
array=[[[self intersectionList]entities]filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"mpoPricingOrg.stringValue contains[cd] %#",item]];
NSLog(#" item is %#",item);
NSLog(#"insie if arr %#",array);
[list appendEntities:array];
NSLog(#"hello %#",[[searchIntersectionField cell]placeholderString]);
}
}
else{
NSLog(#"inside else");
array = [[self searchFieldController] updatePredicateWithFilterText:[searchIntersectionField stringValue] searchArray:[[self intersectionList] entities] searchTableView:intersectionTableView];
NSLog(#"in side else array %#",array);
[list appendEntities:array];
}
[self setIntersectionList:list];
[list release];
[intersectionTableView reloadData];
[intersectionTableView deselectAll:nil];
[super updatePlacard:intersectionTableView];
}
I have called this method in -(void)controltextDidEditing. But when I enter "China" the filter predicate works fine. But when I enter "China,Brazil" it only shows the record for China and not for Brazil. Please suggest a better way of doing it.

How can I sort or add an item to a UITableView the opposite way?

So, I have an UITableView which holds entries for an app I am making. The entriesViewController is its own class, with a .xib file. I have a button that adds a new item.
It does this with the following code:
-(IBAction)newItem:(id)sender {
LEItem *newItem = [[LEItemStore sharedStore] createItem];
NSLog(#"New Item = %#", newItem);
[TableView reloadData];
}
Now this works, and adds the item, however it puts it at the bottom of the list. Since this app logs things for days, I do not want the items in this order. The newest items should be placed at the top of the list. How do I do this? I didn't see any easy way to add items to the table view at the top, but I might be missing something pretty basic.
This doesn't seem like it should be hard, I am probably just overlooking something.
Ideas are welcome.
Edit:
Here is LEItem Store:
//
// LEItemStore.m
//
// Created by Josiah Bruner on 10/16/12.
// Copyright (c) 2012 Infinite Software Technologies. All rights reserved.
//
#import "LEItemStore.h"
#import "LEItem.h"
#implementation LEItemStore
+ (LEItemStore *)sharedStore
{
static LEItemStore *sharedStore = nil;
if (!sharedStore)
sharedStore = [[super allocWithZone:nil] init];
return sharedStore;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedStore];
}
-(id)init
{
self = [super init];
if (self) {
NSString *path = [self itemArchivePath];
allItems = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
if (!allItems)
{
allItems = [[NSMutableArray alloc] init];
}
}
return self;
}
- (NSArray * )allItems
{
return allItems;
}
-(LEItem *)createItem
{
LEItem *p = [LEItem addNewItem];
[allItems addObject:p];
return p;
}
- (void)removeItem:(LEItem *)p
{
[allItems removeObjectIdenticalTo:p];
}
-(void)moveItemAtIndex:(int)from toIndex:(int)to
{
if (from == to) {
return;
}
LEItem *p = [allItems objectAtIndex:from];
[allItems removeObjectAtIndex:from];
[allItems insertObject:p atIndex:to];
}
- (NSString *)itemArchivePath {
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [documentDirectories objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"item.archive"];
}
-(BOOL)saveChanges {
NSString *path = [self itemArchivePath];
return [NSKeyedArchiver archiveRootObject:allItems toFile:path];
}
#end
It looks like the simplest solution would be to modify -[LEItemStore createItem] to this:
-(LEItem *)createItem {
LEItem *p = [LEItem addNewItem];
[allItems insertObject:p atIndex:0];
return p;
}
You can do it even without rearrange the array internally.If you implement the data source and you define this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
Assuming that in your array the oldest objects are at the lowest indexes,supposing that your table view has M rows, return a cell with the format of the object at index M-rowIndex-1.
Unless I'm missing something, after you create the new item, instead of using
[allItems addObject:p];
you just need:
[allItems insertObject:p atIndex:0];
Do you have any type of createdDate or other sortable property on the item? Simply sort your retained list of items (or NSFetchedResultsController) or whatever you are binding to by that property.
You can override the comparison mechanism in your LEItem class, and have it compare dates easily:
-(NSComparisonResult)compare:(LEItem*)otherItem {
return [self.dateCreated compare:otherItem.dateCreated];
}
Then, it's just a matter of using sortArrayUsingSelector: with the selector compare:.

NSDictionary in NSArray search

I'm having a problem with some search code. I have an NSMutableArray, called searchedData, that contains NSDictionaries (one per object). Here's the search code I have now:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[tableData removeAllObjects]; // remove all data that belongs to previous search
if([searchText isEqualToString:#""]||searchText==nil) {
[tableView reloadData];
return;
}
int i = 0;
while (i < [dataSource count]) {
NSDictionary *coolDict = [searchedData objectAtIndex:i];
NSString * title = [coolDict objectForKey:#"TITLE"];
NSString * authorString = [coolDict objectForKey:#"AUTHOR"];
NSRange titleRange = [[title lowercaseString] rangeOfString:[searchText lowercaseString]];
NSRange authorRange = [[authorString lowercaseString] rangeOfString:[searchText lowercaseString]];
if (titleRange.location != NSNotFound || authorRange.location != NSNotFound)
[tableData addObject:title];
i++;
}
[tableView reloadData];
}
It finds the number of entries, then goes to each entry, finds the objects for keys "TITLE" and "AUTHOR", and then displays entries in the UITableView if there is a match.
The problem is that it never displays anything, even if there is a match.
I know the table / dictionaries are not null (I have NSLogged it) so I don't know why it's not working.
You forgot to reload the tableView having added the relevant data to the datasource.
I have improved the coding of the method a bit, and added the missing line.
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[tableData removeAllObjects];// remove all data that belongs to previous search
if (![searchText isEqualToString:#""] || searchText != nil) {
int i = 0;
while (i < [dataSource count]) {
NSDictionary *coolDict = [searchedData objectAtIndex:i];
NSString * title = [coolDict objectForKey:#"TITLE"];
NSString * authorString = [coolDict objectForKey:#"AUTHOR"];
NSRange titleRange = [[title lowercaseString] rangeOfString:[searchText lowercaseString]];
NSRange authorRange = [[authorString lowercaseString] rangeOfString:[searchText lowercaseString]];
if(titleRange.location != NSNotFound || authorRange.location != NSNotFound)
[tableData addObject:title];
i++;
}
}
[tableView reloadData];
}

storing address book records

I have creating an address book application . My AddressController.h class is ---
#interface AddressController : NSObject {
IBOutlet id nameField;
IBOutlet id addressField;
IBOutlet id tableView;
NSMutableArray *records;
}
- (IBAction)addRecord:(id)sender;
- (IBAction)deleteRecord:(id)sender;
- (IBAction)insertRecord:(id)sender;
#end
Implementation class is as follow:-
#implementation AddressController
- (id)init
{
records = [[NSMutableArray alloc] init];
return self;
}
- (NSDictionary *)createRecord
{
NSMutableDictionary *record = [[NSMutableDictionary alloc] init];
[record setObject:[nameField stringValue] forKey:#"Name"];
[record setObject:[addressField stringValue] forKey:#"Address"];
[record autorelease];
return record;
}
- (IBAction)addRecord:(id)sender
{
[records addObject:[self createRecord]];
[tableView reloadData];
}
- (IBAction)deleteRecord:(id)sender
{
int status;
NSEnumerator *enumerator;
NSNumber *index;
NSMutableArray *tempArray;
id tempObject;
if ( [tableView numberOfSelectedRows] == 0 )
return;
NSBeep();
status = NSRunAlertPanel(#"Warning!", #"Are you sure that you want to delete the selected record(s)?", #"OK", #"Cancel", nil);
if ( status == NSAlertDefaultReturn )
{
enumerator = [tableView selectedRowEnumerator]; //enumerator here gets indexes of selected rows
tempArray = [NSMutableArray array];
while ( (index = [enumerator nextObject]) )
{
tempObject = [records objectAtIndex:[index intValue]]; // we store selected rows in temporary array
[tempArray addObject:tempObject];
}
[records removeObjectsInArray:tempArray]; // we delete records from 'records' array which are present in temporary array
[tableView reloadData];
}
}
- (IBAction)insertRecord:(id)sender
{
int index = [tableView selectedRow];
[records insertObject:[self createRecord] atIndex:index];
[tableView reloadData];
}
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [records count];
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
id theRecord, theValue;
theRecord = [records objectAtIndex:rowIndex];
theValue = [theRecord objectForKey:[aTableColumn identifier]];
return theValue;
}
- (void)awakeFromNib
{
[tableView reloadData];
}
#end
I am able to add and delete records to/from address book. But when I start the application again all records are gone. I want to store records somewhere (like in user defaults ) so that when I start the application again existing records are shown in the address book.
I am not getting the idea how to do it using user defaults.
Please suggest solution.
Do not use user defaults for this. You may want to explore Core Data. Another option to explore is NSCoding.
NSCoding will have less of a learning curve, fairly simple to implement. Core Data is tougher to grasp, but would be the wiser choice in the long run.

UITableView and SearchBar problem

I'm trying to add a Search bar to my UITableView. I followed this tutorial: http://clingingtoideas.blogspot.com/2010/02/uitableview-how-to-part-2-search.html.
I'm getting this error if I type a letter in the search box: Rooster(10787,0xa05ed4e0) malloc: *** error for object 0x3b5f160: double free
*** set a breakpoint in malloc_error_break to debug.
This error occurs here:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self handleSearchForTerm:searchString];
return YES;
}
(on the second line)
- (void)handleSearchForTerm:(NSString *)searchTerm {
[self setSavedSearchTerm:searchTerm];
if ([self searchResults] == nil) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[self setSearchResults:array];
[array release];
}
//Empty the searchResults array
[[self searchResults] removeAllObjects];
//Check if the searchTerm doesn't equal zero...
if ([[self savedSearchTerm] length] != 0) {
//Search the whole tableList (datasource)
for (NSString *currentString in tableList) {
NSString *klasString = [[NSString alloc] init];
NSInteger i = [[leerlingNaarKlasList objectAtIndex:[tableList indexOfObject:currentString]] integerValue];
if(i != -1) {
klasString = [klassenList objectAtIndex:(i - 1)];
}
//Check if the string matched or the klas (group of school)
if ([currentString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound ||
[klasString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound) {
//Add to results
[[self searchResults] addObject:currentString];
//Save the klas (group of school). It has the same index as the result (lastname)
NSString *strI = [[NSString alloc] initWithFormat:#"%i", i];
[[self searchResultsLeerlingNaarKlas] addObject:strI];
[strI release];
}
[klasString release];
}
}
}
Can someone help me out?
Regards,
Dodo
The double free error means you have released an object more than needed. Here the suspicious object is klasString.
From your code:
NSString *klasString = [[NSString alloc] init];
...
if(i != -1) {
klasString = [klassenList objectAtIndex:(i - 1)];
}
...
[klasString release];
The assignment inside the if statement
loses reference to the newly allocated NSString, introducing a memory leak
makes the later release apply to the object from klassenList. When klassenList releases its elements, a double free error will occur.