UISearchBar and NSDictionary - objective-c

i want to add to my app a UISearchBar.
I have 3 NSDictionary that contains respectively 3 arrays (sorted). The 3 NSDictionaries have the same key (#"Elements"), stored in a NSMutableArray called listObjects.
At the end of the 3 dicts i have this situation:
[listObjects addObject:dictOne];
[listObjects addObject:dictTwo];
[listObjects addObject:dictThree];
I also have a filteredListContent to store the arrays (for quick searching).
filteredListContent = [[NSMutableArray alloc] initWithCapacity: [listObjects count]];
[filteredListContent addObjectsFromArray: listObjects];
Now, the first question is: does the filteredListContent array store all the 3 dict keys from listObjects?
Then.
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{
[self.filteredListContents removeAllObjects];
NSString *cellTitle;
for (cellTitle in listObjects){
NSComparisonResult result = [cellTitle compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame){
[filteredListContents addObject:cellTitle];
}
}
}
I got a crash as i begin typing in
NSComparisonResult result = [cellTitle compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])];`
line.
Is there supposed to be the key of the dict (#"Elements"), in order to search in all the 3 arrays or?
Edit
Full code
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSDictionary *dictionary = [listObjects objectAtIndex:section];
NSArray *array = [dictionary objectForKey:#"Elements"];
return [array count];
}
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{
NSString *cellTitle;
for (NSDictionary *dict in listaObjects)
{
NSArray *elements = [dict objectForKey: #"Elements"];
for (NSString *cellTitle in elements)
if ([cellTitle compare: searchText options: NSCaseInsensitiveSearch range: NSMakeRange(0, [searchText length])] = NSOrderedSame)])
[filteredListContent addObject: cellTitle];
}}
#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption{
[self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
I got it working, but it shows the contents of all the arrays, even if i type a specific word. What am i doing wrong?

I don't get it. You first add the three dictionaries to filteredListContents and then you remove all objects from the array? That means the array is totally empty again.
Then you enumerate listObjects, which only contains 3 dictionaries, and no strings, using an NSString enumerator. That doesn't make sense.
First, there is no need to do:
[filteredListContents addObjectsFromArray: listObjects];
So remove that line. Now do something like:
for (NSDictionary *dict in listObjects)
{
NSArray *elements = [dict objectForKey: #"Elements"];
for (NSString *cellTitle in elements)
if (cellTitle compare: searchText options: options: NSCaseInsensitiveSearch range: NSMakeRange(0, [searchText length])] = NSOrderedSame)
[filteredListContents addObject: cellTitle];
}
OK, that gives you an array of equal strings. Now what? I'd expect you to collect the cells with that title, but you are not doing that here. You could, instead of storing strings, store dictionaries with the cell title as key and the cell as value. That would make the loop only one level deeper.
As someone wiser than me once said: Show me your problem, not your solution. Then I can help you.
The full code doesn't make any sense to me, sorry. What are you trying to collect actually?

Related

Trying to sort sections in descending order

self.sections = [[NSMutableDictionary alloc] init];
BOOL found;
for (NSDictionary *wine in sortedWines)
{
NSNumber *rate = [wine valueForKey:#"Rate"];
NSString *rateStr = [NSString stringWithFormat:#"%.f", [rate floatValue]];
found = NO;
for (NSString *str in [self.sections allKeys])
{
if ([str isEqualToString:rateStr])
{
found = YES;
}
}
if (!found)
{[self.sections setValue:[[NSMutableArray alloc] init] forKey:rateStr];}
}
for (NSDictionary *wine in sortedWines)
{[[self.sections objectForKey:[NSString stringWithFormat:#"%.f", [[wine valueForKey:#"Rate"] floatValue]] ] addObject:wine];}
// Sort:
for (NSString *key in [self.sections allKeys])
{[[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"Rate" ascending:NO]]];}
This code puts my wines in sections, but it won't sort them in descending order! Could it be because the NSNumber is transformed into NSString? I've tried to make a code using the NSNumber value:
self.sections = [[NSMutableDictionary alloc] init];
BOOL found;
for (NSDictionary *wine in sortedWines)
{
NSNumber *rate = [wine valueForKey:#"Rate"];
found = NO;
for (NSNumber *str in [self.sections allKeys])
{
if ([str isEqualToNumber:rate])
{
found = YES;
}
}
if (!found)
{[self.sections setValue:[[NSMutableArray alloc] init] forKey:rate];}
}
// Loop again to sort wines into their keys
for (NSDictionary *wine in sortedWines)
{[[self.sections objectForKey:[wine valueForKey:#"Rate"]] addObject:wine];}
// Sort each section array
for (NSString *key in [self.sections allKeys])
{[[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"Rate" ascending:NO]]];}
But it gives a warning for
if (!found)
{[self.sections setValue:[[NSMutableArray alloc] init] forKey:rate];}
that says "Incompatible pointer types sending NSNumber ___strong to parameter of type NSString"
If I run the app it crashes with error -[__NSCFNumber localizedCaseInsensitiveCompare:]: unrecognized selector sent to instance 0x1e085810
What do I have to change to make it work and sort the sections in descending order? Thanks.
I don't know if the default selector for sortDescriptorWithKey:ascending: is now caseInsensitiveCompare:, I'm pretty sure it used to be just compare:. In any case, you can use sortDescriptorWithKey:ascending:selector:, instead, and pass compare: for the selector. I think that should fix your second error. Still not sure why you're getting that first error.
You would do much better (and we'd understand you better) if you formatted your code for legibility. Eg:
// Loop again to sort wines into their keys
for (NSDictionary *wine in sortedWines) {
NSArray* section = [self.sections objectForKey:[wine valueForKey:#"Rate"]];
[section addObject:wine];
}
// Sort each section array
NSArray* sortDescriptorArray = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"Rate" ascending:NO]];
for (NSString *key in [self.sections allKeys]) {
NSArray* section = [self.sections objectForKey:key];
[section sortUsingDescriptors:sortDescriptorArray];
}
Among other things, this makes debugging much simpler since you can stop and dump the section arrays.
Or, if you really liked it better the other way, I can highly recommend that you learn APL or LISP instead.

Parse the .plist items

When i'm trying to parse something strange happends.
I'm counting my items with
NSString *bundlePathofPlist = [[NSBundle mainBundle]pathForResource:#"Mything" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:bundlePathofPlist];
NSArray *dataFromPlist = [dict valueForKey:#"some"];
NSMutableArray *data = [NSMutableArray array];
for(int i =0;i<[dataFromPlist count];i++)
{
//NSLog(#"%#",[dataFromPlist objectAtIndex:i]);
[data addObject:[NSNumber numberWithInt:[dataFromPlist count]]];
}
[self setTableData:data];
NSLog(#"%#", tableData);
And then:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tableData count];
}
This works great but then in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
i tried
NSString *bundlePathofPlist = [[NSBundle mainBundle]pathForResource:#"Mything" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:bundlePathofPlist];
NSArray *dataFromPlist = [dict valueForKey:#"some"];
NSLog(#"%#", dataFromPlist);
cell.Data.text = [NSString stringWithFormat:#"%#", dataFromPlist];
return cell;
But the output is:
2012-08-13 23:08:48.130 [30278:707] (
Yeah,
Trol,
LOL,
)
And in my tablecell it also displays as
(
Yeah,
Trol,
LOL,
)
So you got
( yeah, trol, lol )
...in one cell, right? Now, that's natural. If you had read NSLog's or NSString's documentation, you would have found out that the %# format specifier calls an object's description method - which, in turn, for an NSArray object, is a pretty parenthesized, comma separated list of... again, the descriptions of its objects.
What you probably want is
cell.Data.text = [dataFromPlist objectAtIndex:indexPath.row];

How to return arrays object + count IOS

hi at all ,I've this code :
+(NSArray *)splatterUrls
{
NSString *jsonString = [ ApiMethod jsonOfStores];
NSDictionary *results =[jsonString objectFromJSONString];
NSArray *movieArray = [results objectForKey:#"Seasons"];
//int i=0;
// Search for year to match
for (NSDictionary *movie in movieArray)
{
NSNumber *idSplatterMovie = [movie objectForKey:#"Id"];
// NSLog(#" %#", idSplatterMovie );
NSArray *try = [movie objectForKey:#"Episodes"];
// NSLog(#"%#", try);
for (NSDictionary *op in try)
{
if([idSplatterMovie integerValue] == 46)
{
//i++;
NSArray *movieArrayString = [op objectForKey:#"Url"];
// NSLog(#" %#", movieArrayString);
return movieArrayString;
}
}
}
}
I want to return movieArrayString with all his objects and how many object contains in it. I think that I should use this method : + (id)arrayWithObjects:(const id *)objects count:(NSUInteger)count. It's possible? If yes, can you tell me how can use it?
Thank you so much!
by the way , i have to call splatterUrls method and implement in home.m that it is :
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *urlSplatter= [GetSplatterUrlsMovie splatterUrls];
NSLog(#" %#", urlSplatter);
}
Looks good as it is to me.
Do this to return your movies array, array will be equal to your movies array:
NSArray *array = [self splatterUrls];
Then to get the count/number of objects in your array do this, i is equal to the number of objects in the array:
int i = [array count];
What is the problem ??
You return a NSarray ... call the method count on your NSarray object!

cancel button on search bar does not cancel correctly

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

Implementing A Static NSOutlineView

I'm having a hard time scraping together enough snippets of knowledge to implement an NSOutlineView with a static, never-changing structure defined in an NSArray. This link has been great, but it's not helping me grasp submenus. I'm thinking they're just nested NSArrays, but I have no clear idea.
Let's say we have an NSArray inside an NSArray, defined as
NSArray *subarray = [[NSArray alloc] initWithObjects:#"2.1", #"2.2", #"2.3", #"2.4", #"2.5", nil];
NSArray *ovStructure = [[NSArray alloc] initWithObjects:#"1", subarray, #"3", nil];
The text is defined in outlineView:objectValueForTableColumn:byItem:.
- (id)outlineView:(NSOutlineView *)ov objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)ovItem
{
if ([[[tableColumn headerCell] stringValue] compare:#"Key"] == NSOrderedSame)
{
// Return the key for this item. First, get the parent array or dictionary.
// If the parent is nil, then that must be root, so we'll get the root
// dictionary.
id parentObject = [ov parentForItem:ovItem] ? [ov parentForItem:ovItem] : ovStructure;
if ([parentObject isKindOfClass:[NSArray class]])
{
// Arrays don't have keys (usually), so we have to use a name
// based on the index of the object.
NSLog([NSString stringWithFormat:#"%#", ovItem]);
//return [NSString stringWithFormat:#"Item %d", [parentObject indexOfObject:ovItem]];
return (NSString *) [ovStructure objectAtIndex:[ovStructure indexOfObject:ovItem]];
}
}
else
{
// Return the value for the key. If this is a string, just return that.
if ([ovItem isKindOfClass:[NSString class]])
{
return ovItem;
}
else if ([ovItem isKindOfClass:[NSDictionary class]])
{
return [NSString stringWithFormat:#"%d items", [ovItem count]];
}
else if ([ovItem isKindOfClass:[NSArray class]])
{
return [NSString stringWithFormat:#"%d items", [ovItem count]];
}
}
return nil;
}
The result is '1', '(' (expandable), and '3'. NSLog shows the array starting with '(', hence the second item. Expanding it causes a crash due to going 'beyond bounds.' I tried using parentForItem: but couldn't figure out what to compare the result to.
What am I missing?
The example behind the link you included shows an NSDictionary taking care of the subarray stuff, if I'm reading it correctly. So I think your ovStructure should not be an array but a dictionary. But, more fundamentally, I think you should really look into NSTreeController. Unfortunately, NSTreeController is notoriously hard to work with, but improvements were made last year and even I got it working in the end. Good luck.