Obj-C,iOS,如何按值而非键排序,sortedArrayUsingSelector,current@selecto



我想我需要按值而不是Key排序。。。。

这是我填充阵列的地方

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];
}

这是我一段时间以来遇到的问题,上次我看到这个时,我可以找到一个替代方案来排序ArrayUsingSelector比较?

编辑

- (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;
}

有人吗

您显然试图构造一个用于-[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。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

使用-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];
}];

您可以创建一个小模型类Category并在其中实现compare,然后使用compare对这些对象的数组进行排序:。

以下是一些信息-如何对包含自定义对象的NSMutableArray进行排序?

也许您正在寻找NSSortDDescriptor(以及相应的排序方法-[NSArray sortedArrayUsingDescriptors])和朋友?

如果我理解正确,那么您希望做什么来从数据库中获取类别&在表上显示按字母排序的视图,索引在右边&顶部的搜索栏。理想情况下,您希望显示"联系人"应用程序类型的视图。如果这是正确的,使用下面的代码从DB&重建(或重置)它-

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];
}

希望这就是你想要的。

在您的排序函数上,您应该尝试以下操作:

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;
}

最新更新