1

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

Сначала я создать класс 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; 

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

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

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

UPDATE:

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

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

х

- (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, это звучит так, как Код не распознает searchString, но я знаю, что добавил его в Code.h.

UPDATE: Для того, чтобы хранить объекты в 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]; 

} 

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

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

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

ответ

2

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

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

Еще раз мы попросим 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. Это называется обратным вызовом , потому что мы «возвращаем обратно» к объекту, который изначально отправил нам сообщение для выполнения поиска. Мы должны использовать обратные вызовы, а не простые типы возврата, потому что мы использовали makeObjectsPerformSelector, чтобы сообщить каждому Code в массиве codes, чтобы выполнить поиск. Мы никогда не называли непосредственно метод search, поэтому у нас нет способа зафиксировать возвращаемое значение с каждого search. Вот почему его тип возврата - void.

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

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

Here is a link to an excellent language introduction/tutorial который устранит много путаницы.

EDIT В своем последнем комментарии вы сказали, что searchResults было null. Я сказал добавить его как ivar где-то в SearchViewController. В вашем методе Инициализатора для SearchViewController вы должны вызвать

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

В качестве альтернативы вы могли бы «ленивым Initialise» это в matchFound:

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

    [searchResults addObject:matchingCode]; 
} 

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

+0

Я обновил свой вопрос, чтобы показать, где я нахожусь со вторым ответом. Мне кажется, что код не распознает поиск: self как селектор с объектом –

+0

Вы пишете 'search' как метод в' Code'? Вы также добавили его в интерфейс (например, 'code.h'?) –

+0

Нет и нет, теперь я добавил' - (void) search; 'to' Code.h', но я не уверен, как напишите его как метод в 'Code.m' ...' - (void) search {} '? Я использовал этот код, но все равно получаю ту же ошибку. Я пишу это неправильно. –

1

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

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

Вот один из подходов. Есть более простые способы, но этот метод довольно гибкий. В общем, мы собираемся сделать объект Code выполнять работу по поиску собственных строк. Затем мы собираемся дать объекту Code возможность сообщить вызывающему абоненту (т. Е. Объект, которому принадлежит массив codes, предположительно ваш контроллер табличного представления), соответствует ли какая-либо из его строк строке поиска. Затем мы будем использовать метод NSArraymakeObjectsPerformSelector, чтобы рассказать всем его объектам 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 и делает что-то с ним. (Вам не нужно использовать блок: вы можете сохранить ссылку на вызывающего и селектор, чтобы вызывать его вместо этого. Я не буду вдаваться в аргументы для обоих случаев. Другие ответчики могут предлагать альтернативы.)

+0

Это немного выше моего уровня мастерства, и через некоторое время я буду работать, хотя, я ценю вашу помощь. Через некоторое время я сообщу вам. –

+0

Извинения. Есть менее сложные способы достижения вашей цели; Я напишу что-нибудь в выходные. –

Смежные вопросы