我在Objective-C中使用Xcode开发应用程序。 该应用程序有一个TableView与一系列餐厅。我的问题是,当我尝试使用SearchBar时,我使用Title(餐厅的名称作为过滤器),但是当我在过滤器搜索后显示行时,只有标题是正确的。另一个标签和单元格中的图像是错误的(它显示正确的标题,但图像和另一个标签(描述标签)与原始tableview中的第一行相同)。
我必须更改我的cellForRowAtIndexPath
方法,但我现在不知道如何更改它。
这是名为MainTableViewController.h的TableViewController
#import <UIKit/UIKit.h>
@interface MainTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
@property (weak, nonatomic) IBOutlet UIBarButtonItem *barButton;
//@property (nonatomic, strong) NSArray *Images;
//@property (nonatomic, strong) NSArray *Description;
//@property (nonatomic, strong) NSArray *Title;
@property (nonatomic, strong) NSMutableArray *Title;
@property (nonatomic, strong) NSMutableArray *Images;
@property (nonatomic, strong) NSMutableArray *Description;
@property (nonatomic, strong) NSMutableArray *filteredRest;
@property BOOL isFiltered;
@property (strong, nonatomic) IBOutlet UITableView *RestTableView;
@property (strong, nonatomic) IBOutlet UITableView *mySearchBar;
@end
这是我的MainTableViewController.c
#import "MainTableViewController.h"
#import "SWRevealViewController.h"
#import "RestTableViewCell.h"
#import "RestViewController.h"
@interface MainTableViewController ()
@end
@implementation MainTableViewController
@synthesize mySearchBar, filteredRest, isFiltered;
- (void)viewDidLoad {
[super viewDidLoad];
_barButton.target = self.revealViewController;
_barButton.action = @selector(revealToggle:);
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
[self.navigationItem setTitle:@"MadEat"]; /*Cambia el titulo del navigation controller*/
[self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]}]; /*Cambia el color de las letras del navigation controller bar del menu principal*/
[self.navigationController.navigationBar setBarTintColor:[UIColor colorWithRed:27/255.0f green:101/255.0f blue:163/255.0f alpha:1.0f]];
self.navigationController.navigationBar.tintColor = [UIColor whiteColor]; /*Cambia el color del boton de la izquierda*/
self.RestTableView.tableFooterView = [[UIView alloc] init]; /*Esta linea hace que en la tabla solo aparezcan el numero de filas que tienes establecidas, es decir, que las vacias no aparezcan*/
/*Alerta que se muestra solo la primera vez. Está desactivada*/
if (![@"1" isEqualToString:[[NSUserDefaults standardUserDefaults] objectForKey:@"alert"]]) {
[[NSUserDefaults standardUserDefaults] setValue:@"1" forKey:@"alert"];
[[NSUserDefaults standardUserDefaults] synchronize];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Terms of use" message:@"The brands mentioned have no relationship with MadEat and the app has no any liability on that content." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:@"Accept" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:ok];
[self presentViewController:alertController animated:YES completion:nil];
}
_Title = @[@"80 Grados",
@"90 Grados",
@"B&B Babel",
@"Babelia",
@"Bacira",
@"Bar Galleta",
@"Bar Tomate",
@"Barra Atlantica",
@"BaRRa de Pintxos",
@"BaRRa de Pintxos",];
_Description = @[@"Barrio Malasaña",
@"Barrio Retiro",
@"Barrio Chueca",
@"Barrio de Salamanca",
@"Barrio Chamberí",
@"Barrio Malasaña",
@"Barrio Chamberí",
@"Barrio Malasaña",
@"Barrio del Pilar",
@"Barrio Retiro",];
_Images = @[@"80_grados.png",
@"90_grados",
@"babel.png",
@"babelia.png",
@"bacira.png",
@"bar_galleta.png",
@"bar_tomate.png",
@"barra_atlantica.png",
@"barra_de_pintxos.png",
@"barra_de_pintxos.png",];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
//return _Title.count;
if (isFiltered == YES) {
return filteredRest.count;
} else {
return _Title.count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"TableCell";
RestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (isFiltered == YES) {
cell.TitleLabel.text = [filteredRest objectAtIndex:indexPath.row];
} else {
int row = [indexPath row];
cell.TitleLabel.text = _Title[row];
cell.DescriptionLabel.text = _Description[row];
cell.RestImage.image = [UIImage imageNamed:_Images[row]];
}
cell.RestImage.layer.cornerRadius = 6;
cell.RestImage.clipsToBounds = YES;
cell.RestImage.layer.borderWidth = 1;
return cell;
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
/*Cambia el nombre del boton de la izquierda sin afectar al titulo del navigation controller*/
self.navigationItem.backBarButtonItem=[[UIBarButtonItem alloc] initWithTitle: NSLocalizedString (@"Back", nil) style:UIBarButtonItemStylePlain target:nil action:nil];
if ([[segue identifier] isEqualToString:@"ShowDetails"]){
RestViewController *restviewcontroller = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
int row = [myIndexPath row];
restviewcontroller.DetailModal = @[_Title[row],_Description[row],_Images[row]];
}
}
-(void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
//Set our boolean flag
isFiltered = NO;
} else {
//Set our boolean flag
isFiltered = YES;
}
//Alloc and init our filteredData
filteredRest = [[NSMutableArray alloc] init];
for (NSString * restTitle in _Title) {
NSRange restTitleRange = [restTitle rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (restTitleRange.location != NSNotFound) {
[filteredRest addObject:restTitle];
}
}
for (NSString * restDescription in _Description) {
NSRange restDescriptionRange = [restDescription rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (restDescriptionRange.location != NSNotFound) {
//[filteredRest addObject:restDescription];
}
}
for (NSString * restImages in _Images) {
NSRange restImagesRange = [restImages rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (restImagesRange.location != NSNotFound) {
//[filteredRest addObject:restImages];
}
}
//Reload our table view
[_RestTableView reloadData];
}
-(void) searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[mySearchBar resignFirstResponder];
}
@end
最后,这是我的TableViewCell.h,名为RestTableViewCell.h
#import <UIKit/UIKit.h>
@interface RestTableViewCell : UITableViewCell
@property (strong, nonatomic) IBOutlet UILabel *TitleLabel;
@property (strong, nonatomic) IBOutlet UILabel *DescriptionLabel;
@property (strong, nonatomic) IBOutlet UIImageView *RestImage;
@end
这是我的问题:
答案 0 :(得分:2)
显然,您只需将过滤条件应用于Title
数组,而不是过滤Images
和Description
数组。
因此,您需要再使用两个NSMutableArray来保存Images
和Description
的过滤结果。
但我建议您为结果构建一个新的Model
。示例代码供您参考:
@interface Restaurant : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *desc;
@property (nonatomic, copy) NSString *image;
- (instancetype)init:(NSString *)title descripiton:(NSString *)description image:(NSString *)image;
@end
@implementation Restaurant
- (instancetype)init:(NSString *)title descripiton:(NSString *)description image:(NSString *)image {
self = [super init];
if (self != nil) {
self.title = title;
self.desc = description;
self.image = image;
}
return self;
}
@end
@interface RestViewController : UIViewController
@property (nonatomic, strong) Restaurant *DetailModal;
@end
@interface MainTableViewController ()
@property (nonatomic, strong) NSArray<Restaurant *> *originData;
@property (nonatomic, strong) NSMutableArray<Restaurant *> *filteredRest;
@property (nonatomic, assign) Boolean isFiltered;
@end
@implementation MainTableViewController
@synthesize mySearchBar, filteredRest, isFiltered, originData;
- (void)viewDidLoad {
[super viewDidLoad];
originData = @[
[[Restaurant alloc] init:@"80 Grados" descripiton:@"Barrio Malasaña" image:@"80_grados.png"],
[[Restaurant alloc] init:@"90 Grados" descripiton:@"Barrio Retiro" image:@"90_grados"]
];
filteredRest = [NSMutableArray new];
isFiltered = NO;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
//return _Title.count;
if (isFiltered == YES) {
return filteredRest.count;
} else {
return originData.count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"TableCell";
RestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (isFiltered == YES) {
cell.TitleLabel.text = [filteredRest objectAtIndex:indexPath.row].title;
cell.DescriptionLabel.text = [filteredRest objectAtIndex:indexPath.row].desc;
cell.RestImage.image = [UIImage imageNamed:[filteredRest objectAtIndex:indexPath.row].image];
} else {
cell.TitleLabel.text = [originData objectAtIndex:indexPath.row].title;
cell.DescriptionLabel.text = [originData objectAtIndex:indexPath.row].desc;
cell.RestImage.image = [UIImage imageNamed:[originData objectAtIndex:indexPath.row].image];
}
cell.RestImage.layer.cornerRadius = 6;
cell.RestImage.clipsToBounds = YES;
cell.RestImage.layer.borderWidth = 1;
return cell;
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
/*Cambia el nombre del boton de la izquierda sin afectar al titulo del navigation controller*/
self.navigationItem.backBarButtonItem=[[UIBarButtonItem alloc] initWithTitle: NSLocalizedString (@"Back", nil) style:UIBarButtonItemStylePlain target:nil action:nil];
if ([[segue identifier] isEqualToString:@"ShowDetails"]){
RestViewController *restviewcontroller = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
if (isFiltered) {
restviewcontroller.DetailModal = filteredRest[myIndexPath.row];
} else {
restviewcontroller.DetailModal = originData[myIndexPath.row];
}
}
}
-(void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
//Set our boolean flag
isFiltered = NO;
} else {
//Set our boolean flag
isFiltered = YES;
}
//Alloc and init our filteredData
filteredRest = [[NSMutableArray alloc] init];
for (Restaurant *item in originData) {
if ([item.title containsString:searchText]) {
[filteredRest addObject:item];
}
}
//Reload our table view
[self.tableView reloadData];
}
-(void) searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[mySearchBar resignFirstResponder];
}
@end
为您的信息构建一个新的model
对象是非常有效的,因此您不需要将过滤器应用于三个数组,您只需要搜索一次,结果将保留在一个数组中。
PS:编写OC代码时,还有一个针对编码风格的提示,命名变量,以小写字母开头的对象实例,以及以大写字母命名类是最佳做法。例如,TitleLabel
应重命名为titleLabel
等等......
答案 1 :(得分:0)
在这里,您正在过滤单元格并重复使用它们。 你只是在替换文字。您还需要替换图像和数据。
if (isFiltered == YES) {
cell.TitleLabel.text = [filteredRest objectAtIndex:indexPath.row];
} else {
int row = [indexPath row];
cell.TitleLabel.text = _Title[row];
cell.DescriptionLabel.text = _Description[row];
cell.RestImage.image = [UIImage imageNamed:_Images[row]];
}
我不确定,但我认为你还没有清楚地理解可重复使用细胞的概念。您将重用不在视图中的单元格,这意味着iOS框架将为您提供已经使用过的单元格之一,这样它就不必每次在第一个单元格80Grados的情况下重新创建单元格。
因此,在您收到该单元格后,您将替换标题,但保留所有其他内容。这就是为什么你会看到带有新标题标签的旧内容。
这里需要做的是创建一个包装类,它将包含三个属性text,description和imagefile name。
@class Restaurant
@property NSString *title;
@property NString *description;
@property NSString *image;
@end
将您的逻辑与此结合,而不是将所有数据视为单独的数组。这将非常容易维护。将来,您可以使用来自服务器,用户输入或任何其他方式的数据轻松填写该类。处理3种不同阵列的数据不是很可持续的模型。 因此,创建包装类,通过创建NSMutableArray / NSMutableDictionary来填充数据。而不是放置标题,填充整个包装器对象。
[filteredRest addObject: restaurantObj];
以这种方式更改代码
Restaurant *r;
if (isFiltered == YES) {
r = [self.filteredRest objectAtIndex:indexPath.row];
} else {
r = [self.restaurantList objectAtIndex:indexPath.row]];
}
cell.TitleLabel.text = r.title;
cell.DescriptionLabel.text = r.description;
cell.RestImage.image = [UIImage imageNamed:r.image];
如果有任何想法不明确,请告诉我。这只是一个原型,您将不得不在多个地方更改您的代码,但强烈建议您尽快完成这些更改。