Сортировка объектов в NSMutableArray с помощью sortUsingComparator

У меня есть следующий изменяемый массив:

NSMutableArray *persons = [[NSMutableArray alloc]initWithObjects:person1, person2, person3, nil];

где каждый человек является объектом, который содержит свойства (NSInteger) personAge и (NSString*) personName. Теперь я хочу отсортировать этот массив по personAge. Итак, я попробовал следующее:

[persons sortUsingComparator:
     ^NSComparisonResult(id obj1, id obj2)
     {
         Person *p1 = (Person*)obj1;
         Person *p2 = (Person*)obj2;

        return [p1.personAge compare: p2.personAge];

     }];

    NSLog(@"%ld", [persons componentsJoinedByString:@" "]);

Но я получаю сообщение об ошибке «Неверный тип получателя« NSInteger »(он же« длинный »)» в строке возврата. Также у меня есть предупреждение в строке NSLog: «Формат указывает тип« длинный », но аргумент имеет тип« NSString * »». Как это исправить?


person Igal    schedule 11.09.2012    source источник


Ответы (5)


Разве вы не должны использовать что-то подобное вместо этого?

[persons sortUsingComparator:
      ^NSComparisonResult(id obj1, id obj2){

             Person *p1 = (Person*)obj1;
             Person *p2 = (Person*)obj2;
             if (p1.personAge > p2.personAge) {
                return (NSComparisonResult)NSOrderedDescending;
            }

            if (p1.personAge < p2.personAge) {
                return (NSComparisonResult)NSOrderedAscending;
            }
            return (NSComparisonResult)NSOrderedSame;
    }
];

Дело в том, что вы полагаетесь на метод compare, которого нет в NSInteger: это всего лишь определение типа int. Таким образом, вы хотите вместо этого сравнить целочисленное значение и вернуть значение NSComparisonResult, чтобы обозначить порядок вашего объекта соответственно.

person tiguero    schedule 11.09.2012
comment
Да, тот же результат, что и в приведенном выше ответе: ‹Person: 0x10010a720› ‹Person: 0x10010ad20› ‹Person: 0x100108ab0› И тот же вопрос: можно ли каким-либо образом вместо Person: xxxxxxx получить фактический personAge? Таким образом, это будет выглядеть примерно так: 1, 27, 34 и т. д.? - person Igal; 11.09.2012
comment
[p1.personAge intValue] Я думаю, вы печатаете свой объект NSNumber - person tiguero; 11.09.2012
comment
Ладно, теперь я запутался... Вы имели в виду, что я должен сделать что-то вроде этого: if ([p1.personAge intValue] > [p2.personAge intValue]) { return (NSComparisonResult)NSOrderedDescending; }? Затем я все еще получаю сообщение об ошибке «Плохой приемник...». До сих пор не знаю, как напечатать возраст каждого человека... - person Igal; 11.09.2012
comment
Извините, если я неясно выразился, вам просто нужно сделать NSLog в правильном формате: NSLog(@Age: %d, p1.personAge) - person tiguero; 11.09.2012
comment
забудьте о моем комментарии с объектом NSNumber, вы используете NSInteger, это typedef целого числа - person tiguero; 11.09.2012
comment
Нет, я попробовал этот NSLog с %ld (внутри блока ^NSComparisonResult, поскольку p1.personAge не распознается за его пределами) и вообще не получил никакого результата. - person Igal; 11.09.2012
comment
Поскольку %d предназначен для int, а NSInteger — длинное целое, %d просто не работает для NSInteger... - person Igal; 11.09.2012
comment
это зависит от вашей системы... не делайте предположений - person tiguero; 11.09.2012
comment
Сам XCode предложил мне изменить его на %ld :) - person Igal; 11.09.2012
comment
да, потому что у вас 64-битная система...developer.apple.com/library/mac/#documentation/Cocoa/Reference/ прочитать раздел NSInteger - person tiguero; 11.09.2012
comment
Да... Ну, я все еще не могу напечатать personAge, как бы я ни пытался... Очень странно... :-/ - person Igal; 11.09.2012
comment
Бьюсь об заклад, вы все еще используете метод componentJoinedByString - person tiguero; 11.09.2012
comment
Вам необходимо получить доступ к personPage для каждого элемента вашего массива: [[persons valueForKey:@personAge] componentJoinedByString:@] подойдет - person tiguero; 11.09.2012

Вы пытаетесь вызвать compare: для NSInteger, который не является объектом; это typedef для целочисленного типа (либо int, либо long в зависимости от архитектуры).

Кроме того, componentsJoinedByString: возвращает NSString, а не целое число.

Пытаться:

[persons sortUsingComparator:
    ^NSComparisonResult(id obj1, id obj2)
    {
        Person *p1 = (Person*)obj1;
        Person *p2 = (Person*)obj2;

        if (p1.personAge < p2.personAge)
            return NSOrderedAscending;
        if (p1.personAge > p2.personAge)
            return NSOrderedDescending;
        return NSOrderedSame;
 }];

NSLog(@"%@", [persons componentsJoinedByString:@" "]);
person Wevah    schedule 11.09.2012
comment
Я попробовал и получил такой результат: ‹Person: 0x10010a720› ‹Person: 0x10010ad20› ‹Person: 0x100108ab0› Можно ли как-то вместо Person: xxxxxxx получить фактический personAge? Таким образом, это будет выглядеть примерно так: 1, 27, 34 и т. д.? - person Igal; 11.09.2012
comment
[[persons valueForKey:@personAge] componentJoinedByString:@ ] - person Wevah; 11.09.2012
comment
@Igal, вы также можете написать метод описания в своем классе Person, чтобы при выполнении NSLog(@%@,aPerson) вы получали что-то вроде: name:Bill, age:26 вместо ‹Person: 0x10010a720›. - person rdelmar; 11.09.2012

Что касается ошибки «Неверный тип получателя...», то NSInteger — это примитивный тип данных (не класс Objective-C), поэтому вы не можете вызывать для него методы. то, что вы хотите сделать, это следующее:

if (p1.personAge > p2.personAge) {
    return (NSComparisonResult)NSOrderedDescending;
}

if (p1.personAge < p2.personAge) {
    return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;

Предупреждение связано с тем, что @"%ld" является длинной строкой формата (как сказано в предупреждении), а -componentsSeparatedByString: возвращает объект NSString. Правильная строка формата для любого объекта Objective-C — @"%@", поэтому строка должна читаться как NSLog(@"%@", [persons componentsJoinedByString:@" "]);.

person jrtc27    schedule 11.09.2012
comment
Есть ли способ получить настоящий personAge? Таким образом, это будет выглядеть примерно так: 1, 27, 34 и т. д. вместо Person: xxxxxxx в результате? - person Igal; 11.09.2012
comment
Самый простой способ - переопределить метод -description в вашем классе Person, чтобы вернуть то, что вы хотите, чтобы он отображался как. - person jrtc27; 11.09.2012

Как ответ тигегеро, но аккуратнее:

 [people sortUsingComparator:
      ^NSComparisonResult(Person* p1, Person* p2){

            if (p1.personAge > p2.personAge) {
                return NSOrderedDescending;
            }
            else if (p1.personAge < p2.personAge) {
                return NSOrderedAscending;
            }
            else{
                return NSOrderedSame;
            } 
    }
 ];
person malhal    schedule 02.02.2014

person    schedule
comment
Хотя на самом деле это может ответить на вопрос, не могли бы вы уточнить, что на самом деле делает этот код? - person JAL; 28.10.2015