NSUSerDefaults与NSMutableArray按desc顺序排序

时间:2012-12-30 06:56:35

标签: objective-c ios

我正在理解为什么降序排序不能使用以下代码。我想限制前5名和其他逻辑。分数看起来像这样:22 / 30,12 / 18,34 / 38,23 / 32等。我添加/删除SortDescriptor按降序排序,它似乎适用于前3项,但后来没有正确排序。有人可以帮忙吗?

- (NSMutableArray*) method1:(NSString *) mode byScore: (NSString *) score
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSMutableArray *array = [[defaults objectForKey:mode]mutableCopy];

    if (!array)
    {
        array = [[NSMutableArray alloc] init];
    }
    NSLog(@"The content of array is%@", array);

    if ([array count] < 5)
    {
      if (![array containsObject:score])
      {
          [array addObject:score];
          // Need to sort here. But not too sure this is the right place
          NSLog(@"The content of the sorted array upto 5 is%@", array); 
      }
    }
    else
    {
       if (![array containsObject:score])
       {
           if ([array lastObject] < score)
           {
               [array addObject:score];
               // Need to sort here before I remove the last object                   
               [array removeLastObject];
               NSLog(@"The content of the sorted array else is%@",array);
           }
       }
    }
    [defaults setObject:array forKey:mode];
    [defaults synchronize];
    // I want the array in NSUserDefaults to be sorted in desc order
    // don't know what to return here ==> the array object or the defaults object cast    to NSMutableArray?
}

2 个答案:

答案 0 :(得分:1)

辅助功能

static NSComparisonResult CompareFloats( float a, float b )
{
    if ( a < b ) { return NSOrderedAscending ; }
    else if ( a > b ) { return NSOrderedDescending ; }
    return NSOrderedSame ;
}

NSString上的类别

@implementation NSString (Stuff)

-(float)floatValueForFraction
{
    NSArray * components = [ self componentsSeparatedByString:@"/" ] ;
    return [ components[0] floatValue ] / [ components[1] floatValue ] ;
}

@end

你的方法:

- (void)addScore:(NSString*)score forMode:(NSString*)mode
{
    NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
    NSArray * scores = [ defaults objectForKey:mode ] ;

    scores = scores ? [ scores arrayByAddingObject:score ] : @[ score ] ;
    scores = [ scores sortedArrayUsingComparator:^(NSString * a, NSString * b){
        return CompareFloats( [ a floatValueForFraction ], [ b floatValueForFraction ] ) ;
    }]

    if ( scores.count > 5 ) { scores = [ scores subarrayWithRange:(NSRange){ .length = 5 } ] ; }

    [ default setObject:scores forKey:mode ] ;
}

如果您想在调用此方法后获得更新的高分,请使用[ [ NSUserDefaults standardUserDefaults ] objectForKey:<mode> ]。让你的方法只做一件事情会更好。

答案 1 :(得分:0)

排序array的一种方法:

首先按如下方式定义一个块getNumeratorAndDenominatorFromScoreString

BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = ^(NSString *scoreString, NSInteger *numeratorOut, NSInteger *denominatorOut) {
    BOOL res = NO;
    NSArray *components = [scoreString componentsSeparatedByString:@"/"];
    if (components && 
        [components count] == 2) {
        res = YES;
        if (numeratorOut) {
            NSNumber *numeratorNumber = [components objectAtIndex:0];
            *numeratorOut = [numeratorNumber integerValue];
        }
        if (denominatorOut) {
            NSNumber *denominatorNumber = [components objectAtIndex:1];
            *denominatorOut = [denominatorNumber integerValue];
        }
    }
    return res;
};

然后将此块与-[NSArray sortedArrayUsingComparator]一起使用来排序array

NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {
    NSComparisonResult res = NSOrderedSame;

    NSString *score1 = (NSString *)obj1;
    NSString *score2 = (NSString *)obj2;

    NSInteger numerator1, denominator1, numerator2, denominator2;
    BOOL res1, res2;

    res1 = getNumeratorAndDenominatorFromScoreString(score1, &numerator1, &denominator1);
    res2 = getNumeratorAndDenominatorFromScoreString(score2, &numerator2, &denominator2);

    if (res1
        && res2) {
        CGFloat value1 = ((CGFloat)numerator1)/((CGFloat)denominator1);
        CGFloat value2 = ((CGFloat)numerator2)/((CGFloat)denominator2);

        if (value1 > value2) {
            res = NSOrderedDescending;
        } else if (value1 < value2) {
            res = NSOrderedAscending;
        }
    }
    return res;
}];

这将从最小到最大的顺序排列array。要从最大到最小的顺序,只需替换

if (value1 > value2) {
    res = NSOrderedDescending;
} else if (value1 < value2) {
    res = NSOrderedAscending;
}

if (value1 > value2) {
    res = NSOrderedAscending;
} else if (value1 < value2) {
    res = NSOrderedDescending;
}

此方法的可读结构将是[通常不是]伪代码

- (void)addScoreToHighscores:(NSString *)score withMethod:(NSString *)mode
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSArray *currentHighscores = [defaults arrayForKey:mode];
    if (!currentHighscores) currentHighscores = [NSArray array];

    if (![currentHighscores containsObject:score]) {
        currentHighscores = [currentHighscores arrayByAddingObject:score];

        //sort currentHighscores: adapt the above code so that we have
        BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = //as above
        NSArray *newHighscores = [currentHighscores sortedArrayUsingComparator:^(id obj1, id obj2) {
            //as above
        }];

        //truncate newHighscores
        if ([newHighscores count] > 5) {
            newHighscores = [newHighscores subarrayWithRange:NSMakeRange(0,5)];
        }

        [defaults setObject:newHighscores forKey:mode];
    } else {
        //since score is already in currentHighscores, we're done.
        return;
    }
}

如果您需要筛选出不相等的分数但分数相等的评分(@“1/2”和@“5/10”),您需要更多聪明。


以上是草拟的完整代码:

- (void)addScoreToHighscores:(NSString *)score withMethod:(NSString *)mode
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSArray *currentHighscores = [defaults arrayForKey:mode];
    if (!currentHighscores) currentHighscores = [NSArray array];

    if (![currentHighscores containsObject:score]) {
        currentHighscores = [currentHighscores arrayByAddingObject:score];

        //sort currentHighscores: adapt the above code so that we have
        BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = ^(NSString *scoreString, NSInteger *numeratorOut, NSInteger *denominatorOut) {
            BOOL res = NO;
            NSArray *components = [scoreString componentsSeparatedByString:@"/"];
            if (components && 
                [components count] == 2) {
                res = YES;
                if (numeratorOut) {
                    NSNumber *numeratorNumber = [components objectAtIndex:0];
                    *numeratorOut = [numeratorNumber integerValue];
                }
                if (denominatorOut) {
                    NSNumber *denominatorNumber = [components objectAtIndex:1];
                    *denominatorOut = [denominatorNumber integerValue];
                }
            }
            return res;
        };

        NSArray *newHighscores = [currentHighscores sortedArrayUsingComparator:^(id obj1, id obj2) {
            NSComparisonResult res = NSOrderedSame;

            NSString *score1 = (NSString *)obj1;
            NSString *score2 = (NSString *)obj2;

            NSInteger numerator1, denominator1, numerator2, denominator2;
            BOOL res1, res2;

            res1 = getNumeratorAndDenominatorFromScoreString(score1, &numerator1, &denominator1);
            res2 = getNumeratorAndDenominatorFromScoreString(score2, &numerator2, &denominator2);

            if (res1
                && res2) {
                CGFloat value1 = ((CGFloat)numerator1)/((CGFloat)denominator1);
                CGFloat value2 = ((CGFloat)numerator2)/((CGFloat)denominator2);

                if (value1 > value2) {
                    res = NSOrderedDescending;
                } else if (value1 < value2) {
                    res = NSOrderedAscending;
                }
            }
            return res;
        }];

        //truncate newHighscores
        if ([newHighscores count] > 5) {
            newHighscores = [newHighscores subarrayWithRange:NSMakeRange(0,5)];
        }

        [defaults setObject:newHighscores forKey:mode];
    } else {
        //since score is already in currentHighscores, we're done.
        return;
    }
}