Search in UITableView - NSInvalidArgumentException error - objective-c

I'm implementing the search bar in a UITableView (tblFriends) with a "SearchBar and search Display controller"
This is my NSarray of dictionaries filteredFriendsList (equal to friendsList NSarray):
{
gender
id
name
picture
}
I have the table view in a UIViewController, (not in a tableViewController) because the table occupies only half view.
This is the code:
INTERFACE:
#import <UIKit/UIKit.h>
#import "ClasseSingleton.h"
#import "FBConnect.h"
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
NSArray *friendsList;
NSDictionary *friendsDict;
NSMutableArray *filteredFriendsList;
IBOutlet UITableView *tblFriends;
}
#property (nonatomic, retain) NSArray *friendsList;
#property (nonatomic, retain) NSMutableArray *filteredFriendsList;
-(void)getFriends;
#end
IMPLEMENTATION
#import "ViewController.h"
#implementation ViewController
#synthesize friendsList, filteredFriendsList;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[tblFriends setDelegate:self];
[tblFriends setDataSource:self];
}
- (void)getFriends{
NSLog(#"ENTRATO - getFriends");
//Copy ARRAY in other ARRAY
friendsList = [NSArray arrayWithArray:[ClasseSingleton getFriends]];
filteredFriendsList = [NSArray arrayWithArray:[ClasseSingleton getFriends]];
NSLog(#"getFriends : DESCRIPTION\n\n %#", [friendsList description]);
NSLog(#"Count friendslist: %i", [friendsList count]);
[tblFriends reloadData];
}
// *****TABLE MANAGEMENT***** //
//Nuber of cells
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSLog(#"tabella1");
return [filteredFriendsList count];
}
//Populate the table
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPat{
static NSString * cellIdentifier = #"cell";
//Set Style cell
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
friendsDict = [filteredFriendsList objectAtIndex:indexPat.row];
//Set CELL TEXT
NSString *cellValue = [friendsDict objectForKey:#"name"];
NSLog(#"TBL %#", cellValue);
[cell.textLabel setText:cellValue];
return cell;
}
// SEARCH IN TABLE
- (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;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)saearchBar {
[self.filteredFriendsList removeAllObjects];
[self.filteredFriendsList addObjectsFromArray: friendsList];
}
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{
/*
Update the filtered array based on the search text and scope.
*/
[self.filteredFriendsList removeAllObjects]; // First clear the filtered array.
/*
Search the main list for products whose type matches the scope (if selected) and whose name matches searchText; add items that match to the filtered array.
*/
NSString *cellTitle;
for (cellTitle in friendsList){
// for (cellTitle in [friendsDict objectForKey:#"name"]){
NSComparisonResult result = [cellTitle compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame){
[filteredFriendsList addObject:cellTitle];
}
}
}
...
#end
Everytime i put some character in the search bar the app crashes with this error:
'NSInvalidArgumentException', reason: '-[__NSCFDictionary compare:options:range:]: unrecognized selector sent to instance
I hope to solve the problem, it's the 6th days with this error.
Thank you.

You declare filteredFriendsList to be a NSMutableArray, but you're assigning an immuatble NSArray to it here:
filteredFriendsList = [NSArray arrayWithArray:[ClasseSingleton getFriends]];
Change it to this:
filteredFriendsList = [NSMutableArray arrayWithArray:[ClasseSingleton getFriends]];

Related

Can't import NSMutableArray to another class, and save tablecell objects

I have an app that is tableview/pickerview controlled and for each table i have filled with textcellobjects.
Now when customer chooses one row and continue to next tableview I want to save that object in an NSMutableArray that is allocated/initialized in one class and I want to have that class file public so objects can be added from all the different tableview classes into the NSMutableArray.
The first 2 files MotorTVController code is working well, when a tableview cell is clicked the object is added to _myTrimArray, but I want to be able to save next tablecell object in the same _myTrimArray, i try to import the TrimArray.h(2 files last in the code here) with the same save function to MotorTVController to use the savearraycode from it, but is is not working.
So I want TrimArray.h/TrimArray.h to be able to save from all the different classes with tableviews and tableviewcell text values into one NSMutableArray.
I have been struggling with this for almost a week now, I hope someone can give me a solution, I'm kinda new at this, I know this cant be so difficult to solve, but I just don't know how?
//--------- MotorTVController.h
#import "YearPickerTVControllerPolaris.h"
#import "MotorTVController.h"
#import "motorTVCell.h"
#import "brandsTVCell.h"
#import "TrimArray.h"
#interface MotorTVController : YearPickerTVControllerPolaris
#property (nonatomic, strong) NSArray *motorLabelArray;
#property (nonatomic, strong) NSMutableArray *myTrimArray;
#end
//--------- MotorTVController.m file:
#import "MotorTVController.h"
#import "motorTVCell.h"
#import "YearPickerTVControllerPolaris.h"
#import "BackButton.h"
#import "TrimArray.h"
#interface MotorTVController ()
#end
#implementation MotorTVController
#synthesize myTrimArray = _myTrimArray;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
// Getter
- (NSMutableArray *)myTrimArray
{
if (_myTrimArray == nil) {
_myTrimArray = [[NSMutableArray alloc] init];
}
return _myTrimArray;
}
- (void)viewDidLoad
{
UIImage *arrow = [UIImage imageNamed:#"backbutton"];
UIButton *arrowButton = [[UIButton alloc] initWithFrame:CGRectMake(-12, 0, 36, 36)];
[arrowButton setBackgroundImage:arrow forState:UIControlStateNormal];
[arrowButton addTarget:self action:#selector(back)
forControlEvents:UIControlEventTouchUpInside];
UIView* buttonView = [[UIView alloc] initWithFrame:CGRectMake(-12, 0, 36, 36)];
[buttonView addSubview:arrowButton];
UIBarButtonItem * backbutton = [[UIBarButtonItem alloc]
initWithCustomView:buttonView];
[self.navigationItem setLeftBarButtonItem:backbutton];
[super viewDidLoad];
_motorLabelArray = #[#"Original EH12 (4hk)",
#"Honda GX160 (5.5hk)",
#"Subaru EX17 (6hk)",
#"Honda GX200 (6.5hk)",
#"Briggs LO206 (9hk)",
#"Briggs WF206 (11HK)"];
//NSLog(#"%#", _myTrimArray);
}
-(void)back
{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _motorLabelArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"motorTVCell";
motorTVCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
// Configure the cell...
[cell setTintColor:[UIColor blackColor]];
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
[cell setAccessoryType:UITableViewCellAccessoryDetailButton];
NSInteger row = [indexPath row];
cell.motorCellLabel.text = _motorLabelArray[row];
return cell;
}
// Which row is selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath
{
NSInteger rowNumber = indexPath.row;
if (rowNumber == 0)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:0]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:0]);
}
else if (rowNumber == 1)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:1]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:1]);
}
else if (rowNumber == 2)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:2]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:2]);
}
else if (rowNumber == 3)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:3]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:3]);
}
else if (rowNumber == 4)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:4]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:4]);
}
else if (rowNumber == 5)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:5]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:5]);
}
}
#end
//-------------- TrimArray.m
#import "TrimArray.h"
#import "MotorTVController.h"
#interface TrimArray ()
#end
#implementation TrimArray
#synthesize myTrimArray = _myTrimArray;
// Getter
- (NSMutableArray *)myTrimArray
{
if (_myTrimArray == nil) {
_myTrimArray = [[NSMutableArray alloc] initWithCapacity:10];
}
return _myTrimArray;
}
#end
//----------------- TrimArray.h:
#import "MotorTVController.h"
#interface TrimArray : NSMutableArray
#property (nonatomic, strong) NSMutableArray *myTrimArray;
#end
If I understood right your question , you want an arrayObject to be available globally for all the other ViewControllers right ?
If so ,your subclassing form NSMutableArray and give it Property of NSMutableArray is Wrong.
To achieve this , the simplest solution would be to use NSUserDefaults.
To sore the ArrayObject Like below.
// Get the standardUserDefaults object, store your UITableView data array against a key, synchronize the defaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:_trimArray forKey:#"TrimArray"];
[userDefaults synchronize];
To retrieve // you can retrieve the arrayObject from anywhere in your app.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSArray *arrayOfObjects = [userDefaults objectForKey:#"TrimArray"];
// Use 'yourArray' to repopulate your UITableView

UISearchBartextfield -webview called.this method is no longer supported with the new text architecture

I am getting this error and my search function does nothing when the user starts typing a query( XCODE 5.1).
I dont know how the -webView is related to this error as I have not used webView in these files. Any advice would be appreciated. Thank you.
OrdersViewController.h
#import <UIKit/UIKit.h>
#interface OrdersViewController : UITableViewController <UISearchBarDelegate>
//NSmurray is set because we want to edit/move items as well (this will be implemented later)
#property (nonatomic, strong) NSMutableArray *jsonParseArray;
#property (nonatomic, strong) NSMutableArray *ordersArray;
#property (strong, nonatomic) IBOutlet UISearchBar *searchOrders;
#property (nonatomic, strong ) NSMutableArray *orderSearchResults;
#pragma mark -
#pragma mark Class Methods
-(void) retrieveOrderData;
#end
OrdersViewController.m
#import "OrdersViewController.h"
#import "Order.h"
#import "OrderDetailViewController.h"
#define getDataURL #"http://gkhns-macbook-pro.local/gj-3.php"
#interface OrdersViewController ()
#end
#implementation OrdersViewController
#synthesize jsonParseArray, ordersArray;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
//
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.title = #"ORDERS";
[self retrieveOrderData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)searchThroughOrders {
self.orderSearchResults = nil;
//gettig the text that is entered in the search bar and it creates nspredicated self containes the search and this text will be replaced by search field
NSPredicate *orderResultsPredicate = [NSPredicate predicateWithFormat:#"SELF contains [search] %#", self.searchOrders.text];
//filtering the predicate that is set before
self.orderSearchResults = [[self.ordersArray filteredArrayUsingPredicate:orderResultsPredicate] mutableCopy];
}
//detect when the user typed in the search
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[self searchThroughOrders];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//are we in regular table view or search display view? Lets check that
if (tableView == self.tableView)
{
return ordersArray.count;
}
else{
[self searchThroughOrders];
// Return the number of rows in the section.
return self.orderSearchResults.count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"OrderCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle=UITableViewCellStyleDefault;
}
if (tableView== self.tableView)
// Configure the cell...
{Order *orderObject;
orderObject = [ordersArray objectAtIndex:indexPath.row];
cell.textLabel.text=orderObject.order_id;
cell.detailTextLabel.text=orderObject.firstname;
}
else
{
cell.textLabel.text = self.orderSearchResults [indexPath.row];
}
//accessory
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Navigation
//In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([[segue identifier] isEqualToString:#"pushOrderDetailView"]){
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Order* object = [ordersArray objectAtIndex:indexPath.row];
[[segue destinationViewController] getOrder:object];
}
}
#pragma mark -
#pragma mark Class Methods
-(void) retrieveOrderData{
NSURL * url = [NSURL URLWithString:getDataURL];
NSData * data = [NSData dataWithContentsOfURL:url];
jsonParseArray=[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//orders array
ordersArray= [[NSMutableArray alloc]init];
//loop through the jason array
for (int i=0; i<jsonParseArray.count; i++)
{
//create the order object
NSString *oId = [[jsonParseArray objectAtIndex:i] objectForKey:#"order_id"];
NSString *eMail = [[jsonParseArray objectAtIndex:i] objectForKey:#"email"];
NSString *fName = [[jsonParseArray objectAtIndex:i] objectForKey:#"firstname"];
NSString *lName = [[jsonParseArray objectAtIndex:i] objectForKey:#"lastname"];
NSString *sName = [[jsonParseArray objectAtIndex:i] objectForKey:#"store_name"];
NSString *iPrefix = [[jsonParseArray objectAtIndex:i] objectForKey:#"invoice_prefix"];
NSString *pAddress1 = [[jsonParseArray objectAtIndex:i] objectForKey:#"payment_address_1"];
NSString *sPaymentAddress2 = [[jsonParseArray objectAtIndex:i] objectForKey:#"payment_address_2"];
//add order to orders array
[ordersArray addObject:[[Order alloc]initWithOrderId: (NSString *)oId andInvoicePrefix: (NSString*)iPrefix andStoreName:(NSString*)sName andFirstName:(NSString*)fName andLastName:(NSString*)lName andEmail:(NSString*)eMail andPaymentAddress1:(NSString*)pAddress1 andPaymentAddress2:(NSString*)sPaymentAddress2]];
}
//reload the view
[self.tableView reloadData];
}
#end
I was using searchbar only instead of search bar and the search display controller which may have caused this issue.
Also done a few changes to the searchdisplay controller implementation below which fixed the issue.
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self searchThroughOrders:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
-(void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView{
[tableView registerClass:[CustomOrdersCell class] forCellReuseIdentifier:#"OrderCell"];
}
-(void)searchThroughOrders:(NSString *)searchText scope:(NSString*)scope {
//getting the text that is entered in the search bar and it creates nspredicated self containes the search and this text will be replaced by search field
NSPredicate *orderResultsPredicate = [NSPredicate predicateWithFormat:#"order_id contains[c] %#", searchText];
//filtering the predicate that is set before
_orderSearchResults = [ordersArray filteredArrayUsingPredicate:orderResultsPredicate];
}

Hiding an autocomplete UITableView that was created programmatically

I'm building an application with an autocomplete UITableView from this tutorial. I have the autocomplete functionality working properly, but I would like the UITableView-autocomplete drop down to disappear when the word is clicked on or when it is touched up outside. I'm not sure how to set up a delegate when the object is set up programmatically. I've only done this using the interface builder.
.h
#interface slrpViewController : UIViewController<UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource>
{
NSMutableArray *dataArray;
NSMutableData *receivedData;
NSMutableArray *pastUrls;
NSMutableArray *autocompleteUrls;
UITableView *autocompleteTableView;
}
#property(nonatomic, retain) IBOutlet UITextField *eWordEntered;
#property (nonatomic, retain) NSMutableArray *pastUrls;
#property (nonatomic, retain) NSMutableArray *autocompleteUrls;
#property (retain, nonatomic) NSMutableData *responseData;
#property (nonatomic, retain) UITableView *autocompleteTableView;
-(void)setReceivedData:(NSMutableData*)pReceivedData;
-(NSMutableData *) getReceivedData;
-(void) getAutoCompleteArray;
-(void)searchAutocompleteEntriesWithSubstring:(NSString *)substring;
.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self getAutoCompleteArray];
pastUrls = [[NSMutableArray alloc] init];
NSLog(#"In the viewDidLoad and pasturl is: %#", self.pastUrls);
self.autocompleteUrls = [[NSMutableArray alloc] init];
autocompleteTableView = [[UITableView alloc] initWithFrame:CGRectMake(210, 225, 310, 120) style:UITableViewStylePlain];
self.autocompleteTableView.delegate = self;
self.autocompleteTableView.dataSource = self;
autocompleteTableView.scrollEnabled = YES;
autocompleteTableView.hidden = YES;
[self.view addSubview:autocompleteTableView];
-(void)setReceivedData:(NSMutableData*)pReceivedData
{
receivedData = pReceivedData;
}
-(NSMutableData *) getReceivedData{
return receivedData;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *e = nil;
NSError *error = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: receivedData options: NSJSONReadingMutableContainers error: &e];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:receivedData
options:kNilOptions
error:&error];
seneca_word.ids = [jsonDict objectForKey:#"ids"];
NSArray *array_ids = [jsonDict objectForKey:#"ids"];
NSString *ids = array_ids[0];
seneca_word.ids = ids;
for (id key in jsonDict)
{
NSLog(#"key: %#, value: %#", key, [jsonDict objectForKey:key]);
NSLog(#"The value of bases by itself is: %#", [jsonDict objectForKey:#"bases"]);
}
if (!jsonArray)
{
NSLog(#"Error parsing JSON: %#", e);
}
else
{
if([jsonDict objectForKey:#"english"] != nil){
pastUrls = [jsonDict objectForKey:#"bases"];
}
else{
//Some of JSON object that I don't want to use here
}//else
}//(void)connectionDidFinishLoading
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {
[autocompleteUrls removeAllObjects];
for(NSString *curString in pastUrls) {
NSRange substringRange = [curString rangeOfString:substring];
if (substringRange.location == 0) {
[autocompleteUrls addObject:curString];
}
}
[autocompleteTableView reloadData];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
autocompleteTableView.hidden = NO;
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
return YES;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
return autocompleteUrls.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
static NSString *AutoCompleteRowIdentifier = #"AutoCompleteRowIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:AutoCompleteRowIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AutoCompleteRowIdentifier];
}
cell.textLabel.text = [autocompleteUrls objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
self.eWordEntered.text = selectedCell.textLabel.text;
if(tableView == autocompleteTableView){
//The autocomplete table view is the one that fired the didSelect delegate method
//So hide the autocomplete table.
//do whatever else you need to do to empty the autocompleteTableView's data source
//or/and simply hide the table after that
[autocompleteTableView setHidden:YES];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//When the user clicks outside of the uitableview it will disappear
[autocompleteTableView setHidden:YES];
}
As you can see I populate the autocomplete UITableView with JSON data that I'm getting from a RESTful API.
I'm getting the warning, Assigning to 'id<UITableViewDelegate>' from incompatible type 'ViewController *const __strong' for the lines:
self.autocompleteTableView.delegate = self;
self.autocompleteTableView.dataSource = self;
I imagine once I get the delegate stuff sorted out I'll be able to do what I want. I did some research and tried to create a delegate class but wasn't able to get that solution working. I'm not even sure if that's the right way to go about this as I usually do this stuff by interface builder and not programmatically. Any direction or help is greatly appreciated. Thanks!
You should be using the tableView's didSelectCellAtIndexPathRow delegate method to identify user taps on a cell from a tableView. It's ok if you created your tableView progammatically.
Simply make sure the UIViewController conforms to the UITableViewDelegate and UITableViewDataSource` protocols.
make sure you set the tableView's delegate and dataSource property to self.
Implement the didSelectCellAtIndexPathRow delegate method in your viewController's .m file like so:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
}
Then inside that delegate method you need to help detect from which tableView your didSelect method got fired from as you only want to hide the autocomplete table when the user selects a cell from that table. So you do a simple tableView check like so:
if(tableView == autocompleteTableView){
//The autocomplete table view is the one that fired the didSelect delegate method
//So hide the autocomplete table.
//do whatever else you need to do to empty the autocompleteTableView's data source
//or/and simply hide the table after that
[autocompleteTableView setHidden:YES];
}
You probably also want to make sure that you set the autocompleteTableView hidden property to NO when the user types in something in the textfield so that the auto complete can show appear again.
And thats all buddy.
try setting self.autocompleteTableView.hidden = YES;

UISearchBarDelegate on UITableView with Sections Issue

I'm having issues with implementing the UISearchBarDelegate on my UITableView with sections issue where every time I try to search for something inside the UITableView, either it doesn't display the desired result or it crashes the app with an error saying:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
Here's inside my header file:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate>
{
UITableView *mainTableView;
NSMutableArray *contentsList;
NSMutableArray *searchResults;
NSString *savedSearchTerm;
NSMutableArray *ivSectionKeys;
NSMutableDictionary *ivSectionContents;
}
#property (nonatomic, retain) IBOutlet UITableView *mainTableView;
#property (nonatomic, retain) NSMutableArray *contentsList;
#property (nonatomic, retain) NSMutableArray *searchResults;
#property (nonatomic, copy) NSString *savedSearchTerm;
#property (nonatomic, retain) NSMutableArray *sectionKeys;
#property (nonatomic, retain) NSMutableDictionary *sectionContents;
- (void)handleSearchForTerm:(NSString *)searchTerm;
#end
while this is inside my implementation file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize mainTableView;
#synthesize contentsList;
#synthesize searchResults;
#synthesize savedSearchTerm;
#synthesize sectionKeys = ivSectionKeys;
#synthesize sectionContents = ivSectionContents;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSMutableArray *keys = [[NSMutableArray alloc] init];
NSMutableDictionary *contents = [[NSMutableDictionary alloc] init];
NSString *colorKey = #"Colors";
NSString *clothingKey = #"Clothing";
NSString *miscKey = #"Misc";
[contents setObject:[NSArray arrayWithObjects:#"Red", #"Blue", nil] forKey:colorKey];
[contents setObject:[NSArray arrayWithObjects:#"Pants", #"Shirt", #"Socks", nil] forKey:clothingKey];
[contents setObject:[NSArray arrayWithObjects:#"Wankle Rotary Engine", nil] forKey:miscKey];
[keys addObject:clothingKey];
[keys addObject:miscKey];
[keys addObject:colorKey];
self.sectionKeys = keys;
self.sectionContents = contents;
// Restore search term
if (self.savedSearchTerm)
{
self.searchDisplayController.searchBar.text = self.savedSearchTerm;
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Save the state of the search UI so that it can be restored if the view is re-created.
self.savedSearchTerm = self.searchDisplayController.searchBar.text;
self.searchResults = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.mainTableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)handleSearchForTerm:(NSString *)searchTerm
{
self.savedSearchTerm = searchTerm;
if (self.searchResults == nil)
{
NSMutableArray *array = [[NSMutableArray alloc] init];
self.searchResults = array;
array = nil;
}
[self.searchResults removeAllObjects];
if ([self.savedSearchTerm length] != 0)
{
for (NSString *currentString in self.sectionContents)
{
if ([currentString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
{
[self.searchResults addObject:currentString];
}
}
}
}
#pragma mark -
#pragma mark UITableViewDataSource Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger sections = [self.sectionKeys count];
return sections;
}
- (NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section
{
NSString *key = [self.sectionKeys objectAtIndex:section];
return key;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
NSString *key = [self.sectionKeys objectAtIndex:section];
NSArray *contents = [self.sectionContents objectForKey:key];
NSInteger rows;
if (tableView == [[self searchDisplayController] searchResultsTableView])
rows = [self.searchResults count];
else
rows = [contents count];
NSLog(#"rows is: %d", rows);
return rows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *key = [self.sectionKeys objectAtIndex:indexPath.section];
NSArray *contents = [self.sectionContents objectForKey:key];
NSString *contentForThisRow = [contents objectAtIndex:indexPath.row];
if (tableView == [self.searchDisplayController searchResultsTableView])
contentForThisRow = [self.searchResults objectAtIndex:indexPath.row];
else
contentForThisRow = [contents objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = contentForThisRow;
return cell;
}
#pragma mark -
#pragma mark UITableViewDelegate Methods
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self handleSearchForTerm:searchString];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
self.savedSearchTerm = nil;
[self.mainTableView reloadData];
}
#end
I think my issue is inside my for-loop but I'm not really sure.
You need to update all of your table view data source and delegate methods to handle both tables (you only do this in some):
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger sections = [self.sectionKeys count];
return sections;
}
should be:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (tableView == self.tableView) {
NSInteger sections = [self.sectionKeys count];
return sections;
} else { // assume it's the search table
// replace this with the actual result
return numberOfSectionsForSearchTable;
}
}

display image cell in tableview

I tried to display imagecells in tableview, but the program crashes..
here's my imageCell class:
#interface ImageCell : NSTextFieldCell {
NSImage *imageIcon;
NSString *labelStr;
}
#property (retain) NSImage *imageIcon;
#property (retain) NSString *labelStr;
- (id) initWithLabel:(NSString *) labelString imageName:(NSString *) imageString;
when the program runs, it crashes with error message:
-[NSTextFieldCell labelStr]: unrecognized selector sent to instance 0x10011f160
but I already provide my own imageCell class...
is there anything I did wrong, thanks!!!
here's my tableview delegate & datasource:
- (void) awakeFromNib {
self.list = [[NSMutableArray alloc] init];
[self.list addObject:[[ImageCell alloc] initWithLabel:#"Library" imageName:#"album.tiff"]];
// set first cell here
NSTableColumn *col = [[self.tableView tableColumns] objectAtIndex:0];
[col setDataCell:[list objectAtIndex:0]];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)pTableView {
return [self.list count];
}
- (id)tableView:(NSTableView *)pTableView objectValueForTableColumn:(NSTableColumn *)pTableColumn row:(int)pRow {
ImageCell *imageCell = (ImageCell *)[self.list objectAtIndex:pRow];
return imageCell.labelStr;
}
- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell
forTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)pRow {
ImageCell *imageCell = (ImageCell *)cell;
imageCell.image = [[self.list objectAtIndex:pRow] imageIcon];
[imageCell setTitle:imageCell.labelStr];
}
The docs don't specify any guarantee that the table columns returned by -tableColumns are in any particular order. Try asking for -tableColumnWithIdentifier: (and make sure your table columns have identifiers specified in the nib).