Добавление searchBar в ваш TableView - PullRequest
1 голос
/ 20 января 2012

Я бы хотел добавить функцию поиска к TableView в моем приложении.Я заполняю таблицу с NSArray, который имеет x количество Objects, которое содержит 3 NSStrings.Вот как я создаю это NSArray:

Сначала я создаю класс Code.h:

#import <Foundation/Foundation.h>

@interface Code : NSObject

@property (nonatomic, strong) NSString *codeName;
@property (nonatomic, strong) NSString *codeNumber;
@property (nonatomic, strong) NSString *codeDesc;

@end

Затем я синтезирую эти NSStrings в Code.m.

Теперь в моем SearchViewController.m, вот как я создаю свой набор данных:

NSMutableArray *codes;
codes = [[NSMutableArray alloc] init];

Code *c = [[Code alloc] init];
[c setCodeNumber:@"1"];
[c setCodeName:@"First Title Here"];
[c setCodeDesc:@"I might write a desc in here."];
[codes addObject:c];

c = [[Code alloc] init];
[c setCodeNumber:@"2"];
[c setCodeName:@"Second Title Here"];
[c setCodeDesc:@"2nd desc would be written here."];
[codes addObject:c];

и так далее ...

Вот как я его отображаю: cellForRowAtIndexPath:

 Code *c = [codes objectAtIndex:indexPath.row];
 NSString *fused = [NSString stringWithFormat:@"%@ - %@",[c codeNumber],[c codeName]];
 cell.textLabel.text = fused;
 return cell;

Итак, теперь, когда вы знаете, как структурированы и отображаются мои данные, у вас есть представление о том, как искать NSArray или, возможно (предпочтительно) TableCells, которые уже были созданы?

Я прошел через несколько онлайн-уроков, касающихся Adding a Search Bar to a TableView, но все они написаны для использования настройки массивов с использованием простого arrayWithObjects.

SIDETHOUGHT: Можно ли мне построить arrayWithObjects:@"aaa-1",@"bbb-2",@"ccc-3"... из моих данных?Если мне удастся справиться с этим, я смогу использовать эти учебники для заполнения своих ячеек и их поиска!

ОБНОВЛЕНИЕ:

Ваш второй ответ имеет для меня больше смысла!Спасибо за это.Я полагаю, что выполнил вашу инструкцию, но я получаю "- [Поиск кода:]: нераспознанный селектор, отправленный на экземпляр 0x6a2eb20`, когда эта строка нажата.

  1. Я добавил @property (nonatomic, strong) NSString *searchString; к Code.h и синтезировал его в Code.m
  2. Я добавил NSMutableSet *searchResults; к SearchViewController.h * @interface
  3. Я добавил ваши методы performSearchWithString и matchFound к SearchViewController.m
  4. Непосредственно под теми, кого я добавил, чтобы вызвать performSearchWithString

x

- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchString {
NSLog(@"%@",searchString); //Just making sure searchString is set
[self performSearchWithString:searchString];
[self.tableView reloadData];
}

Ошибка срабатывает при запуске [codes makeObjectsPerformSelector:@selector(search:) withObject:self];. Я запутался b /c похоже, что Code не распознает searchString, но я знаю, что добавил его в Code.h.

ОБНОВЛЕНИЕ: чтобы хранить объекты в searchResults, мне пришлось заменить searchResults на NSMutableSet в NSMutableArray и измените - (void)matchFound:(Code *) matchingCode {} на это:

-(void) matchFound:(Code *) matchingCode {

Code *match = [[Code alloc] init];

if (searchResults.count == 0) {
    searchResults = [[NSMutableArray alloc] init];
    [match setCodeName:[matchingCode codeName]];
    [match setCodeNumber:[matchingCode codeNumber]];
    [match setCodeDesc:[matchingCode codeDesc]];
    [searchResults addObject:match];
}
else
{
    match = [[Code alloc] init];
    [match setCodeName:[matchingCode codeName]];
    [match setCodeNumber:[matchingCode codeNumber]];
    [match setCodeDesc:[matchingCode codeDesc]];
    [searchResults addObject:match];

}

С несколькими другими твиками у меня есть рабочая панель поиска для моего tableView. Спасибо, Тим Кемп!

О, я также искал поиск без учета регистра. NSRange rangeName = [codeName rangeOfString: searchString options:NSCaseInsensitiveSearch];

Я надеюсь, что этот вопрос и ответ будут полезны для следующей цели обучения разработчика - cч этот вопрос!

Ответы [ 2 ]

2 голосов
/ 21 января 2012

Упрощенный подход

Вы попросили более простое решение.Этот не такой гибкий, но он достигнет тех же результатов, что и мой предыдущий ответ для этого конкретного случая.

Еще раз мы попросим Code найти его строки для нас.На этот раз мы собираемся пропустить SearchRequest и обратный вызов блока и реализовать его напрямую.

В вашем SearchViewController вы создадите два метода.Один для поиска и один обратный вызов для обработки любых результатов по мере их возвращения.Вам также понадобится контейнер для хранения соответствующих Code объектов (предположительно, может совпадать более одного). Вам также нужно добавить метод к Code, чтобы сообщить ему, что такое строка поиска.

  1. Добавьте ивар NSMutableSet с именем searchResults к SearchViewController.
  2. Добавьте свойство типа NSString * с именем searchString к Code
  3. Добавитьметод поиска до SearchViewController.Это то, что вы позвоните, когда захотите начать поиск по всем вашим кодам:

    -(void) performSearchWithString:(NSString *) searchString {
       // Tell each Code what string to search for
       [codes makeObjectsPerformSelector:@selector(setSearchString:) withObject:searchString];
       // Make each code perform the search
       [codes makeObjectsPerformSelector:@selector(search:) withObject:self];
     }
    
  4. Тогда вам также потребуется обратный вызов в SearchViewController.Это так, что ваши Code объекты могут сообщить SearchViewController, что они нашли совпадение:

    -(void) matchFound:(Code *) matchingCode {
      [searchResults addObject:matchingCode];
      // do something with the matching code. Add it to a different table 
      // view, or filter it or whatever you need it to do.
    }
    

Однако учтите, что у вас нет использовать изменяемый набор searchResults;Вы можете просто вызвать другой метод, чтобы немедленно добавить возвращенный результат в какой-то другой список на экране.Это зависит от потребностей вашего приложения.

В Code добавьте метод поиска, как и раньше, но вместо параметра SearchRequest мы передадим ссылку на SearchViewController:

    - (void) search:(SearchViewController *) searchVC {
      // Search each string in turn
      NSRange rangeNum = [codeNumber rangeOfString : searchString];
      NSRange rangeName = [codeName rangeOfString : searchString];
      NSRange rangeDesc = [codeDesc rangeOfString: searchString];
      if (rangeNum.location != NSNotFound || rangeName.location != NSNotFound || rangeDesc.location != NSNotFound) {
         [searchVC matchFound:self];
      }
    }

Вы видите, как это работает?Если в какой-либо из строк есть совпадение (|| означает 'или'), тогда передайте self (что в точности означает, как это звучит: текущий объект, который выполняет этот код прямо сейчас) обратно методу в контроллере представленияназывается searchVC.Это называется callback , потому что мы «перезваниваем» объекту, который первоначально отправил нам сообщение для поиска.Мы должны использовать обратные вызовы, а не простые возвращаемые типы, потому что мы использовали makeObjectsPerformSelector, чтобы указать каждому Code в массиве codes выполнить поиск.Мы сами никогда не вызывали метод search, поэтому у нас нет способа получить возвращаемое значение из каждого search.Вот почему его тип возвращаемого значения равен void.

. Вы можете расширить matchFound, чтобы получить дополнительный параметр, который определяет, в какой строке совпадение было (т.е. çodeNumber, codeName или codeDesc.)Рассмотрите enums как один хороший подход для передачи таких данных.

Надеюсь, что это немного проще.

Вот ссылка на превосходное введение в язык / учебное пособие который устранит большую путаницу.

РЕДАКТИРОВАТЬ В своем последнем комментарии вы сказали, что searchResults было нулевым.Я сказал добавить его в виде ивара где-то в SearchViewController.В вашем методе инициализации для SearchViewController вы должны вызвать

searchResults = [[NSMutableSet alloc] initWithCapacity:50]` // Choose some sensible number other than 50; enough to hold the likely number of matching Code objects.

В качестве альтернативы вы можете «лениво инициализировать» его в matchFound:

- (void) matchFound:(Code *) matchingCode {
  if (!searchResults)
    searchResults = [[NSMutableSet alloc] initWithCapacity:50];

  [searchResults addObject:matchingCode];
}

Хотя, если вы сделаете это, вы должны знатьв любом другом месте, к которому у вас есть доступ к searchResults, может оказаться, что оно пустое, если matchCode: никогда ранее не вызывался.

1 голос
/ 21 января 2012

Оригинальный, гибкий и более сложный ответ

Мне немного непонятно, что вы пытаетесь сделать, поэтому я продолжу с вашим названием "Поиск каждогострока в каждом объекте массива. "В вашем случае ваши Code s имеют три строки, а ваш массив имеет несколько Code s.Я предполагаю, что вам нужен способ сообщить вызывающей стороне - код, который хочет выполнить поиск - который соответствует Code.

Вот один из подходов.Есть более простые способы, но эта техника довольно гибкая.В общем, мы собираемся заставить объект Code выполнять поиск своих собственных строк.Затем мы собираемся дать объекту Code возможность сообщить вызывающей стороне (т.е. объекту, которому принадлежит массив codes, предположительно, ваш контроллер табличного представления), соответствует ли какая-либо из его строк строке поиска.Затем мы будем использовать метод NSArray makeObjectsPerformSelector, чтобы сообщать всем его Code объектам о своем поиске.Мы будем использовать блок для обратного вызова.

Во-первых, добавьте метод search к Code (в интерфейсе или в качестве категории в зависимости от вашего дизайна), что-то вроде этого:

-(void) search:(SearchRequest *) request {
  // Search using your favourite algorithm
  // eg bool matches = [searchMe [request searchString]];
  if (matches) {
    [request foundMatch:self];
  }
}

SearchRequest является новым.Это место, где можно связать строку поиска и блок обратного вызова.Это выглядит примерно так:

@interface SearchRequest
@property (retain) NSString * searchString;
@property (copy) void (^callback)(Code *);
- (id) initWithSearchString:(NSString *) search callback:(void (^)(Code *)) callback;
- (void) foundMatch:(Code *) matchingCode;
@end

@implementation SearchRequest
// synthesize...
// initialiser sets ivars
- (void) foundMatch:(Code *) matchingCode {
  callback(matchingCode);
}

Блок callback - это наш способ обратной связи с вызывающей стороной.

Если вы хотите выполнить поиск, создайте объект SeachRequestсо строкой, которую вы ищете, и блок, который содержит метод для вызова, когда вы получите совпадение.Это будет выглядеть так в вызывающей программе:

- (void) performASearchWithString:(NSString *) searchForMe {
    SearchRequest * req = [[SearchRequest alloc] initWithSearchString:searchForMe 
                                     callback:^(Code * matchingCode) {
                                                  [self foundAHit:matchingCode];
                                     }];

    [codes makeObjectsPerformSelector:@selector(search:) withObject:req];
}

Затем вам нужно внедрить foundAHit в вызывающую программу, которая берет соответствующий Code и что-то с ним делает.(Вам не нужно использовать блок: вы можете сохранить ссылку на вызывающего и селектор, чтобы вызвать его вместо этого. Я не буду вдаваться в аргументы для любого случая здесь. Другие ответчики могут предложить альтернативы.)

...