정렬 디스크립터
원본 : https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/SortDescriptors/Articles/Creating.html#//apple_ref/doc/uid/20001845-BAJEAIEE
정렬 디스크립터(Sort Decriptor
)는 집합 객체의 원소가 되는 객체들을 비교하는 규칙을 묘사하는 객체이다. NSSortDescriptor
의 인스터는 슬 만들어서 어떤 키를 기준으로 정렬할 것인지, 올림차순으로 정렬할 것인지 내림차순으로 정렬할 것인지를 지정할 수 있다. 또한 기본 비교 메소드인 compare:
외에 다른 비교 메소드를 사용하도록 지정할 수 있다.
정렬 디스크립터 자체가 정렬을 하지는 않는다는 것을 기억하자. 이 객체는 객체들이 어떻게 정렬되어야 하는지를 설명할 뿐이다. 실제 정렬은 NSArray나 NSMutableArray가 수행하게 된다.
NSSortDescriptor를 사용하여 정렬을 지정하기
커스텀 클래스인 Employee
의 집합으로 구성된 배열이 하나 있다고 가정하자. Employee
객체는 firstName
과 lastName
, 고용일과 나이정보를 프로퍼티로 제공하고 있다고 하자. 이 때 나이로 배열을 정렬해보자. 다음 예제는 NSSortDescriptor를 사용하여 나이의 오름차순으로 정렬된 배열을 얻는 방법을 설명한다.
NSSortDescriptor *ageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" acending:YES];
NSArray *sortDescriptors = @[ageDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];
이 때 눈여겨 보아야 하는 부분은 하나의 디스크립터 인스턴스가 아니라 디스크립터들을 원소로 가지는 배열을 사용해야 한다는 점이다. 각각의 디스크립터는 순차적으로 적용되어 여러가지 키에 대해서 한 번에 정렬이 가능하다.
만약 고용일을 기준으로 정렬하고 싶다면 이 배열에 고용일을 기준으로 한 디스크립터를 추가하면 된다. 다음 예제는 한 번에 여러 가지의 기준을 적용하여 배열을 정렬하는 방법이다.
NSSortDescriptor *ageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES];
NSSortDescriptor *hireDateDescriptor = [[NSSortDescriptor alloc] initWithKey:@"hireDate" ascending:YES];
NSArray *sortDescriptors = @[ageDescriptor, hireDateDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];
직원들의 이름을 기준으로 정렬를 하는 경우에는 조금 생각해봐야 하는 문제가 있다. 만약 직원 이름을 사용자 로케일에 따른 사전순으로 정렬하고 대소문자 구분을 하지 않고 싶다면 (NSString의 기본 compare:는 대소문자 구분을 한다.) 비교 메소드를 따로 지정해야 한다.
커스텀 비교 메소드 지정하기
앞서 살펴본 예제는 기본 compare:
를 사용한다. 하지만 이름은 지역화된 문자열을 비교해야 하고 대소문자 구분을 하지 않아야 하므로 기본 compare:
를 쓸 수 없다고 했다. 이 때는 localizedStandardCompare:
를 사용해야 한다.
NSSortDescriptor *lastNameDesciptor = [[NSSortDescriptor alloc] initWithKey:@"lastName" ascending:YES selector:@selector(localizedStandardCompare:)];
NSSortDescriptor *firstNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"firstName" ascending:YES selector:@selector(localizedStandardCompare:)];
NSArray *sortDescriptors = @[lastNameDesciptor, firstNameDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];
다음 목록은 정렬 디스크립터를 사용하여 정렬할 수 있는 파운데이션 클래스들이다.
- compare: – NSString, NSMutableString, NSDate, NSCalendarDate, NSValue, NSNumber
- caseInsensitiveCompare: NSString, NSMutableString
- localizedCompare: – NSString, NSMutableString
- localizedCaseInsensitiveCompare: – NSString, NSMutableString
- localizedStandardCompare: – NSString, NSMutableString
또한, 이 다음에 설명할 조건을 만족하는 메소드를 구현하면, 커스텀 메소드를 사용하여 정렬을 구현할 수 있다.
집합 객체의 요건
집합에 대해 NSSortDescriptor
를 적용하여 정렬하려면 다음과 같은 조건을 만족해야 한다.
- 각각의 객체는 정렬하고자 하는 키에 대해 키밸류 코딩으로 접근할 수 있어야 한다.
- 집합내의 모든 객체는 지정한 키에 대해서 비교를 위한 메소드를 구현하고 있어야 한다. 커스텀 메소드가 지정되지 않았다면 기본 메서드를 사용해야 하는데 이 때 각 객체는
compare:
메소드를 기본적으로 구현해야 한다. - 비교 메소드는 단 하나의 파라미터만 받아, 그 파라미터와 객체 자신을 비교해서 적절한
NSComparisonResult
값을 반환해야 한다.
NSComparisonResult 는 두 객체사이의 상대적인 순서를 의미하는 정수값으로 다음과 같이 선언되어 있다.
enum {
NSOrderedAscending = -1,
NSOrderedSame,
NSOrderedDescending
};
typedef NSInteger NSComparisonResult;