Как сортировать NSMutableArray с пользовательскими объектами в Objective-C
Узнайте три эффективных метода сортировки NSMutableArray, содержащей пользовательские объекты, по свойствам NSDate в Objective-C. Сравните подходы с использованием compare:, NSSortDescriptor и блоков с полными примерами кода.
Как отсортировать NSMutableArray, содержащий пользовательские объекты в Objective-C?
У меня есть NSMutableArray объектов Person, и мне нужно отсортировать их по свойству birthDate, которое является NSDate. Я видел упоминания о методе sortedArrayUsingSelector, но я не уверен, как реализовать правильный селектор для этого случая.
В Java я бы обычно реализовывал интерфейс Comparable или использовал Collections.sort с пользовательским компаратором. Какой эквивалентный подход существует в Objective-C для сортировки пользовательских объектов по определенному свойству?
Сортировка NSMutableArray с кастомными объектами в Objective-C
Для сортировки NSMutableArray, содержащего кастомные объекты в Objective-C, существует три основных подхода: реализовать метод compare: в вашем кастомном классе, использовать NSSortDescriptor с Key-Value Coding или использовать метод sortedArrayUsingComparator: с блоком. Для сортировки объектов Person по birthDate (свойству NSDate) подход с методом compare: наиболее похож на интерфейс Comparable в Java, в то время как NSSortDescriptor предлагает большую гибкость для сложных сценариев сортировки.
Содержание
- Реализация метода compare:
- Использование NSSortDescriptor
- Использование sortedArrayUsingComparator:
- Рекомендации по производительности
- Полный пример реализации
Реализация метода compare:
Наиболее прямой подход к сортировке кастомных объектов в Objective-C - это реализация метода compare: в вашем кастомном классе. Этот метод похож на метод compareTo в Java и позволяет сравнивать объекты напрямую.
Сначала добавьте метод compare: в реализацию класса Person:
// Person.m
- (NSComparisonResult)compare:(Person *)otherObject {
return [self.birthDate compare:otherObject.birthDate];
}
Затем вы можете отсортировать массив с помощью метода sortedArrayUsingSelector::
NSArray *sortedArray = [personArray sortedArrayUsingSelector:@selector(compare:)];
Этот подход имеет несколько преимуществ:
- Он чистый и инкапсулирован внутри класса
- Он следует естественному порядку сортировки (по возрастанию по умолчанию)
- Он похож на паттерн интерфейса Comparable в Java
Однако у этого подхода есть ограничения:
- Вы можете иметь только один метод
compare:на класс - Он не позволяет использовать разные критерии сортировки (например, по убыванию)
- Изменения в логике сортировки требуют изменения реализации класса
Примечание: Метод
compare:возвращает значение перечисленияNSComparisonResult:NSOrderedAscending,NSOrderedSameилиNSOrderedDescending.
Использование NSSortDescriptor
NSSortDescriptor предоставляет более гибкий подход к сортировке массивов кастомных объектов с использованием Key-Value Coding (KVC). Это особенно полезно, когда вам нужно сортировать по нескольким критериям или динамически изменять порядок сортировки.
Для сортировки по birthDate по возрастанию:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"birthDate" ascending:YES];
NSArray *sortedArray = [personArray sortedArrayUsingDescriptors:@[sortDescriptor]];
Для сортировки по убыванию:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"birthDate" ascending:NO];
NSArray *sortedArray = [personArray sortedArrayUsingDescriptors:@[sortDescriptor]];
Вы также можете сортировать по нескольким критериям:
NSSortDescriptor *sortByDate = [[NSSortDescriptor alloc]
initWithKey:@"birthDate" ascending:YES];
NSSortDescriptor *sortByName = [[NSSortDescriptor alloc]
initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = @[sortByDate, sortByName];
NSArray *sortedArray = [personArray sortedArrayUsingDescriptors:sortDescriptors];
Согласно Учебнику по языку Objective-C, этот подход relies на KVC и может быть немного медленнее, чем прямые вызовы методов.
Использование sortedArrayUsingComparator:
Этот современный подход использует блок для определения логики сравнения, предлагая гибкость без изменения ваших кастомных классов:
NSArray *sortedArray = [personArray sortedArrayUsingComparator:^NSComparisonResult(Person *person1, Person *person2) {
return [person1.birthDate compare:person2.birthDate];
}];
Для сортировки по убыванию:
NSArray *sortedArray = [personArray sortedArrayUsingComparator:^NSComparisonResult(Person *person1, Person *person2) {
return [person2.birthDate compare:person1.birthDate]; // Обратное сравнение
}];
Этот подход похож на Collections.sort в Java с кастомным Comparator и предоставляет:
- Гибкость без изменения классов
- Легкое переключение между порядком возрастания и убывания
- Возможность выполнения сложных сравнений внутри блока
Рекомендации по производительности
При выборе между этими подходами учитывайте производительность:
-
Прямые вызовы методов (метод
compare:) обычно являются самыми быстрыми, так как они избегают накладных расходов на передачу сообщений и KVC. -
Компараторы на основе блоков немного медленнее, чем прямые вызовы методов, но более гибкие.
-
NSSortDescriptor является самым медленным из-за накладных расходов KVC, но предлагает наибольшую гибкость для сложных сценариев сортировки.
Как указано в документации Riptutorial, “Методы -compare: и на основе блоков будут значительно быстрее, в общем, чем использование NSSortDescriptor, так как последний relies на KVC.”
Для приложений с критически важной производительностью и большими массивами рекомендуется метод compare:. Для большинства приложений подход на основе блоков обеспечивает хороший баланс между производительностью и гибкостью.
Полный пример реализации
Вот полный пример, демонстрирующий все три подхода:
Person.h:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSDate *birthDate;
@end
Person.m:
#import "Person.h"
@implementation Person
// Метод 1: Реализация метода compare:
- (NSComparisonResult)compare:(Person *)otherObject {
return [self.birthDate compare:otherObject.birthDate];
}
@end
Пример сортировки:
// Создание тестовых данных
NSMutableArray *people = [NSMutableArray array];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
[people addObject:[[Person alloc] initWithName:@"Alice" birthDate:[formatter dateFromString:@"1990-05-15"]]];
[people addObject:[[Person alloc] initWithName:@"Bob" birthDate:[formatter dateFromString:@"1985-12-20"]]];
[people addObject:[[Person alloc] initWithName:@"Charlie" birthDate:[formatter dateFromString:@"1992-01-10"]]];
// Метод 1: Использование метода compare:
NSArray *sortedByCompare = [people sortedArrayUsingSelector:@selector(compare:)];
NSLog(@"Отсортировано методом compare: %@", sortedByCompare);
// Метод 2: Использование NSSortDescriptor
NSSortDescriptor *dateDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES];
NSArray *sortedByDescriptor = [people sortedArrayUsingDescriptors:@[dateDescriptor]];
NSLog(@"Отсортировано через NSSortDescriptor: %@", sortedByDescriptor);
// Метод 3: Использование компаратора на основе блока
NSArray *sortedByComparator = [people sortedArrayUsingComparator:^NSComparisonResult(Person *person1, Person *person2) {
return [person1.birthDate compare:person2.birthDate];
}];
NSLog(@"Отсортировано через компаратор блока: %@", sortedByComparator);
Источники
- How do I sort an NSMutableArray with custom objects in it? - Stack Overflow
- Sorting array with custom objects - Riptutorial
- Sorting an NSMutableArray with Custom Objects in Objective-C - Repeato
- Sort array of objects by their NSDate property - Stack Overflow
- Creating and Using Sort Descriptors - Apple Developer Documentation
Заключение
Сортировка NSMutableArray с кастомными объектами в Objective-C по свойствам NSDate может быть выполнена тремя основными способами:
- Реализуйте метод
compare:в вашем кастомном классе для чистой, инкапсулированной сортировки, наиболее похожей на интерфейс Comparable в Java - Используйте
NSSortDescriptorдля гибкой сортировки с Key-Value Coding, особенно полезно при множественных критериях сортировки - Используйте
sortedArrayUsingComparator:с блоками для максимальной гибкости без изменения классов
Для большинства приложений подход на основе блоков обеспечивает лучший баланс между производительностью и гибкостью. Выбирайте метод compare: для сценариев с критически важной производительностью и NSSortDescriptor, когда вам нужны возможности сложной сортировки или динамического изменения порядка сортировки.
Каждый подход имеет свое место в вашем наборе инструментов Objective-C, и понимание всех трех сделает вас более универсальным разработчиком iOS.