Пользовательский буквенно-цифровой порядок NSSortDescriptor

Я пытаюсь отсортировать NSArray в произвольном алфавитном порядке. Дело в том, что у меня есть массив со строками, содержащими состояния объектов.

Доступные состояния: entered, process, ready, done.

Теперь, когда я сортирую их нормально (в алфавитном порядке), порядок будет неверным (сделано, введено, обработано, готово).

Я попробовал следующий код, чтобы заказать его правильно:

NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"state" ascending:YES comparator:^(id obj1, id obj2) {
    if ([obj1 isEqualToString:@"entered"] && [obj2 isEqualToString:@"process"]) {
        return (NSComparisonResult) NSOrderedAscending;
    }
    else if ([obj1 isEqualToString:@"process"] && [obj2 isEqualToString:@"entered"]) {
        return (NSComparisonResult) NSOrderedDescending;
    }
    else if ([obj1 isEqualToString:@"process"] && [obj2 isEqualToString:@"ready"]) {
        return (NSComparisonResult) NSOrderedAscending;
    }
    else if ([obj1 isEqualToString:@"ready"] && [obj2 isEqualToString:@"process"]) {
        return (NSComparisonResult) NSOrderedDescending;
    }
    else if ([obj1 isEqualToString:@"ready"] && [obj2 isEqualToString:@"done"]) {
        return (NSComparisonResult) NSOrderedAscending;
    }
    else if ([obj1 isEqualToString:@"done"] && [obj2 isEqualToString:@"ready"]) {
        return (NSComparisonResult) NSOrderedDescending;
    }
    else {
        return (NSComparisonResult) NSOrderedSame;
    }
}];

Я также пытался использовать только первые буквы слов, но это тоже не сработало.

Когда я использую этот компаратор, он просто не заказывает соответственно. массив сохраняет «старый» порядок.

Что я обедаю неправильно? Разве я не правильно понял компараторы сортировки?

Спасибо за помощь, с уважением, Джулиан


person Julian F. Weinert    schedule 30.03.2012    source источник


Ответы (2)


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

Обычная реализация включает enum, который автоматически увеличивается, если вы определяете его следующим образом:

typedef enum {
   entered = 0,
   processed,
   ready,
   done
 } State;

Сортировка теперь становится тривиальной.

Ваш state должен иметь тип State, который практически является целым числом. Вам нужно будет обернуть его в NSNumber, если вы хотите использовать NSDictionary или NSArray, но это, безусловно, более читабельно, если вы создадите пользовательский объект с @property типа State.

person Mundi    schedule 01.04.2012
comment
Эй, Мунди! Отличный подход, спасибо! Но теперь: как мне преобразовать NSString (с именами состояний) в объект типа state? Я не могу изменить представление из базы данных, потому что мое приложение — это всего лишь оболочка iOS для веб-приложения. Спасибо однако! - person Julian F. Weinert; 03.04.2012
comment
Так же, как и с другими полями JSON или XML. Сопоставьте их со свойствами вашего пользовательского объекта одно за другим. В этом случае, возможно, просто со строкой операторов if. - person Mundi; 03.04.2012

Я должен ответить, потому что у меня здесь много кода. Теперь у меня все заработало. Но есть забавная ошибка :)

NSString *str1 = (NSString *)obj1;
NSString *str2 = (NSString *)obj2;

if ([str1 isEqualToString:@"entered"] && [str2 isEqualToString:@"progress"]) {
    return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:@"entered"] && [str2 isEqualToString:@"ready"]) {
    return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:@"entered"] && [str2 isEqualToString:@"done"]) {
    return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:@"progress"] && [str2 isEqualToString:@"entered"]) {
    return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:@"progress"] && [str2 isEqualToString:@"ready"]) {
    return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:@"progress"] && [str2 isEqualToString:@"done"]) {
    return (NSComparisonResult) NSOrderedAscending;
}
else if ([str1 isEqualToString:@"ready"] && [str2 isEqualToString:@"entered"]) {
    return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:@"ready"] && [str2 isEqualToString:@"progress"]) {
    return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:@"ready"] && [str2 isEqualToString:@"done"]) {
    return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:@"done"] && [str2 isEqualToString:@"entered"]) {
    return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:@"done"] && [str2 isEqualToString:@"progress"]) {
    return (NSComparisonResult) NSOrderedDescending;
}
else if ([str1 isEqualToString:@"done"] && [str2 isEqualToString:@"ready"]) {
    return (NSComparisonResult) NSOrderedDescending;
}
else {
    return (NSComparisonResult) NSOrderedSame;
}

Теперь ошибка: когда я меняю направление заказа (ascending:YES / NO), направление правильное каждый второй раз, когда я заказываю ascending:YES (введено, выполняется, готово, выполнено). В противном случае это немного неправильно: введено, прогресс, сделано, готово.

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

Спасибо, Мунди, но я думаю, что буду продолжать использовать свой нечеткий стиль. Я новичок в Cocoa/Objective C, и сейчас этот способ имеет для меня больше смысла. Тем не менее спасибо за ваши усилия!!

person Julian F. Weinert    schedule 02.04.2012