Obj-C, iOS, Как мне отсортировать по значению, а не по ключу, sortedArrayUsingSelector, в настоящее время @selector (сравнить :)] - PullRequest
1 голос
/ 30 мая 2011

Мне нужно отсортировать по значению вместо ключа, я думаю ....

Вот где я заполняю свои массивы

const char *sql = "select cid, category from Categories ORDER BY category DESC";
sqlite3_stmt *statementTMP;

int error_code = sqlite3_prepare_v2(database, sql, -1, &statementTMP, NULL);
if(error_code == SQLITE_OK) {
    while(sqlite3_step(statementTMP) == SQLITE_ROW)
    {
        int cid = sqlite3_column_int(statementTMP, 0);
        NSString *category = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statementTMP, 1)];

        NSArray *arr=[[NSArray alloc]initWithObjects:category,nil];

        [arrayTmp setObject:arr forKey:[NSString stringWithFormat:@"%i",cid]];
        [self.cidList addObject:[NSString stringWithFormat:@"%i",cid]];

        [category release];
        [arr release];
    }
}
sqlite3_finalize(statementTMP);
sqlite3_close(database);

self.allCategories = arrayTmp;
[arrayTmp release];

Вот метод, в котором массивы пересортированы.

- (void)resetSearch {

NSMutableDictionary *allCategoriesCopy = [self.allCategories mutableDeepCopy];
self.Categories = allCategoriesCopy;
[allCategoriesCopy release];
NSMutableArray *keyArray = [[NSMutableArray alloc] init];
[keyArray addObject:UITableViewIndexSearch];
[keyArray addObjectsFromArray:[[self.allCategories allKeys] 
                               sortedArrayUsingSelector:@selector(compare:)]];
self.keys = keyArray;
[keyArray release];
}

Это проблема, с которой я столкнулся в течение некоторого времени, когда я в последний раз смотрел на нее, я мог найти альтернативу sortedArrayUsingSelector сравнение?

EDIT

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];

NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [Categories objectForKey:key];

static NSString *SectionsTableIdentifier = @"SectionsTableIdentifier";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
                         SectionsTableIdentifier ];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                   reuseIdentifier: SectionsTableIdentifier ] autorelease];
}

cell.textLabel.text = [nameSection objectAtIndex:row];
return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];

NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [Categories objectForKey:key];

NSLog(@"the selected cid is = %i",[key intValue]); 

selectButton.enabled = YES;
}

Любой

Ответы [ 6 ]

4 голосов
/ 02 июня 2011

Вы явно пытаетесь создать массив для использования в -[UITableviewDatasource sectionIndexTitlesForTableView:]. Таким образом, вам нужен массив, который выглядит следующим образом (псевдокод):

[UITableViewIndexSearch, 0_sectionTitle, 1_sectionTitle, 2_sectionTitle, ...]

Я думаю, что ваша непосредственная проблема заключается в том, что вы пытаетесь добавить строковую константу UITableViewIndexSearch в массив перед сортировкой , что делает невозможным его окончание первым элементом если все остальные ваши элементы не отсортированы ниже U.

Исправить несложно, просто добавьте константу после сортировки. Вы можете очистить код, пока вы на нем:

  NSMutableArray *secIdx=[NSMutableArray arrayWithCapacity:[[self.allCategories allKeys] count]];
  [secIdx addObjectsFromArray:[self.allCategories allKeys]];
  [secIdx sortUsingSelector:@selector(compare:)];
  [secIdx insertObject:UITableViewIndexSearch atIndex:0];
  self.keys=secIdx;

Обратите внимание, что secIdx автоматически выпущен, поэтому вам не нужно его выпускать.

Помимо этой проблемы, в вашем коде много ненужных / опасных элементов, которые сделают ваше приложение хрупким и сложным в обслуживании.

  1. Вы используете init для объектов, для которых вы можете использовать удобные методы с автоматическим освобождением. Инициатива создает риск утечки памяти, но не дает никаких преимуществ.
  2. Вам необходимо заключить скалярные значения в объекты, чтобы ими можно было легко управлять в коллекциях.
  3. Вы используете ненужный массив.

Первый блок можно переписать так:

const char *sql = "select cid, category from Categories ORDER BY category DESC";
sqlite3_stmt *statementTMP;

int error_code = sqlite3_prepare_v2(database, sql, -1, &statementTMP, NULL);
if(error_code == SQLITE_OK) {
    NSNumber *cidNum; //... move variable declerations outside of loop
    NSString *category; //.. so they are not continously recreated
    [self.allCategories removeAllObjects]; //... clears the mutable dictionary instead of replacing it
    while(sqlite3_step(statementTMP) == SQLITE_ROW){
        cidNum=[NSNumber numberWithInt:(sqlite3_column_int(statementTMP, 0))]; 
        category=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statementTMP, 1)];
        //... adding the autoreleased category and cidNum to array/dictionary automatically retains them
        [self.allCategories addObject:category forKey:cidNum]; 
        [self.cidList addObject:cidNum];

        //[category release]; ... no longer needed
        //[arr release]; ... no longer needed
    }
}
sqlite3_finalize(statementTMP);
sqlite3_close(database);

//self.allCategories = arrayTmp; ... no longer needed
//[arrayTmp release]; ... no longer needed
3 голосов
/ 30 мая 2011

Используйте -sortedArrayUsingComparator: (или -sortedArrayUsingFunction:context:, если вы не можете использовать блоки).Пример:

NSDictionary *categories = [self allCategories];
NSArray *keysSortedByValue = [[categories allKeys] sortedArrayUsingComparator:
^(id left, id right) {
    id lval = [categories objectForKey:left];
    id rval = [categories objectForKey:right];
    return [lval compare:rval];
}];
1 голос
/ 30 мая 2011

Возможно, вы ищете NSSortDescriptor (и соответствующий метод сортировки, -[NSArray sortedArrayUsingDescriptors]) и друзей?

1 голос
/ 30 мая 2011

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

Вот некоторая информация - Как отсортировать NSMutableArray с пользовательскими объектами в нем?

0 голосов
/ 06 июня 2011

Если я правильно понял, что вы хотите сделать, чтобы получить категории из базы данных и отобразить их в табличном представлении с алфавитной сортировкой, индексом справа и строкой поиска вверху.В идеале вы хотели бы отобразить вид приложения Контакты.Если это правильно, используйте приведенный ниже код для извлечения элементов из БД и перестройки (или сброса) его -

const char *sql = "select cid, category from Categories ORDER BY category DESC";
sqlite3_stmt *statementTMP;

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

int error_code = sqlite3_prepare_v2(database, sql, -1, &statementTMP, NULL);
if(error_code == SQLITE_OK) {
    while(sqlite3_step(statementTMP) == SQLITE_ROW) {
         int cid = sqlite3_column_int(statementTMP, 0);
         NSString *category = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statementTMP, 1)];

         NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
         [dict setObject:category forKey:@"Category"];
         [dict setObject:[NSNumber numberWithInt:cid] forKey:@"CID"];

         [arrayTmp addObject:dict];
         [dict release];
         [category release];
    }
}

sqlite3_finalize(statementTMP);
sqlite3_close(database);

self.allCategories = arrayTmp;
[arrayTmp release];

, а затем перестройте элементы с помощью этой функции -

- (void)rebuildItems {
    NSMutableDictionary *map = [NSMutableDictionary dictionary];

    for (int i = 0; i < allCategories.count; i++) {
        NSString *name = [[allCategories objectAtIndex:i] objectForKey:@"Category"];
        NSString *letter = [name substringToIndex:1];
        letter = [letter uppercaseString];

        if (isdigit([letter characterAtIndex:0]))
              letter = @"#";

        NSMutableArray *section = [map objectForKey:letter];
        if (!section) {
            section = [NSMutableArray array];
            [map setObject:section forKey:letter];
        }
        [section addObject:[allCategories objectAtIndex:i]];
    }

    [_items release];
    _items = [[NSMutableArray alloc] init];
    [_sections release];
    _sections = [[NSMutableArray alloc] init];

    NSArray* letters = [map.allKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
    for (NSString* letter in letters) {
        NSArray* items = [map objectForKey:letter];
        [_sections addObject:letter];
        [_items addObject:items];
    }
}

Теперь, отображаяэлементы в tableView, используйте методы ниже -

#pragma mark -
#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView {
    if (_sections.count)
        return _sections.count;
    else
        return 1;
}

- (NSInteger)tableView:(UITableView*)tableView sectionForSectionIndexTitle:(NSString *)title
               atIndex:(NSInteger)index {

    if (tableView.tableHeaderView) {
        if (index == 0) {
            [tableView scrollRectToVisible:tableView.tableHeaderView.bounds animated:NO];
            return -1;
        }
    }

    NSString* letter = [title substringToIndex:1];
    NSInteger sectionCount = [tableView numberOfSections];
    for (NSInteger i = 0; i < sectionCount; i++) {
         NSString* section = [tableView.dataSource tableView:tableView titleForHeaderInSection:i];
         if ([section hasPrefix:letter]) {
             return i;
         }
    }

    if (index >= sectionCount) {
        return sectionCount-1;
    } else {
        return index;
    }
}


- (NSArray*)lettersForSectionsWithSearch:(BOOL)withSearch withCount:(BOOL)withCount {
    if (isSearching)
        return nil;

    if (_sections.count) {
        NSMutableArray* titles = [NSMutableArray array];
        if (withSearch) {
            [titles addObject:UITableViewIndexSearch];
        }
        for (NSString* label in _sections) {
            if (label.length) {
                NSString* letter = [label substringToIndex:1];
                [titles addObject:letter];
            }
        }
        if (withCount) {
            [titles addObject:@"#"];
        }
        return titles;
    } else {
        return nil;
    }
}


- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return [self lettersForSectionsWithSearch:YES withCount:NO];
}


- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
    if (_sections.count) {
        NSArray* items = [_items objectAtIndex:section];
        return items.count;
    } else {
        return _items.count;
    }
}


- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (_sections.count) 
        return [_sections objectAtIndex:section];

    return nil;
}


- (id)tableView:(UITableView *)tableView objectForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (_sections.count) {
        NSArray *section = [_items objectAtIndex:indexPath.section];
        return [section objectAtIndex:indexPath.row];
    } else {
        return [_items objectAtIndex:indexPath.row];
    }
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // Create your UITableViewCell.

    // Configure the cell.
    NSDictionary *dict = [self tableView:tableView objectForRowAtIndexPath:indexPath];
    cell.textLabel.text = [dict objectForKey:@"Category"];
            cell.detailTextLabel.text = [NSString stringWithFormat:%d, [[dict objectForKey:@"CID"] intValue]];
    return cell;
}

#pragma mark -
#pragma mark Table view delegate


- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if (isSearching)
        return nil;

    NSString *title = @"";
    if (_sections.count) {      
        title = [[_sections objectAtIndex:section] substringToIndex:1];
    } else {
        return nil;
    }

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 20)];
    view.backgroundColor = [UIColor colorWithRed:(58/255.0) green:(27/255.0) blue:(6/255.0) alpha:1.0];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 1, 50, 18)];
    label.textColor = [UIColor whiteColor];
    label.backgroundColor = [UIColor clearColor];
    label.font = [UIFont boldSystemFontOfSize:17.0];
    label.text = title;

    [view addSubview:label];
    [label release];

    return [view autorelease];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSDictionary *dict = [self tableView:tableView objectForRowAtIndexPath:indexPath];

    NSLog(@"selected row id:%d, name:%@", [dict objectForKey:@"Category"], [[dict objectForKey:@"CID"] intValue]);
}

Остальная часть реализует UISearchBarDelegate и реализует поиск tableView, который может быть выполнен с использованием кода ниже:

- (void)searchBar:(UISearchBar *)searchbar textDidChange:(NSString *)searchText {

    [_sections removeAllObjects];
    [_items removeAllObjects];

    if([searchText isEqualToString:@""] || searchText == nil) {
        [self rebuildItems];
        return;
    }

    NSInteger counter = 0;
    for(NSDictionary *dict in allCategories) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSRange r = [[dict objectForKey:@"Category"] rangeOfString:searchText options:NSCaseInsensitiveSearch];
        if(r.location != NSNotFound) {
            if(r.location == 0) {
                [_items addObject:dict];
            }
        }
        counter++;
        [pool release];
    }

    [contactList reloadData];
}

Надеюсь, что это то, чтоВы ищете.

0 голосов
/ 06 июня 2011

В вашей функции сортировки вы должны попробовать это:

NSArray *cntxt; //im not sure this is the correct type that ur using on keyArray
[keyArray addObjectsFromArray:[self.allCategories allKeys]];
[keyArray sortUsingFunction:compareFunction context:cntxt];

И функцию сравнения, которую вы изменяете в соответствии с вашими потребностями

NSInteger compareFunction(id x, id y, void *context) {
    //NSArray *ctxt = context;
    NSArray *c1 = x;
    NSArray *c2 = y;

    if ([c1 value] < [c2 value])
        return NSOrderedDescending;
    else if ([c1 value] > [c2 value])
        return NSOrderedAscending;
    else 
        return NSOrderedSame;
}

Редактировать: После прочтения ваших комментариев и после просмотра вашегокод, похоже, что ваш keyArray как объекты типа NSString, поэтому вы должны изменить:

NSInteger compareFunction(id x, id y, void *context) {
    //NSString *ctxt = context;
    NSString *c1 = x;
    NSString *c2 = y;
    NSComparisonResult result;
    result = [c1 compare:c2];

    if (result<0)
        return NSOrderedAscending;
    else if (result>0)
        return NSOrderedDescending;
    else 
        return NSOrderedSame;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...