数组NSArray排序
问题你使用数组来组织自定义对象,希望对象按照各自属性值的顺序出现在列表中。
解决方案
为用于数组排序的每个属性创建NSSortDescriptor 对象,将所有这些NSSortDescriptor对象放到一个数组中,该数组将会在后面用作参数。使用NSArray 类的sortedArrayUsing-Descriptors:方法并将NSSortDescriptor 对象数组作为参数传递进去,结果会返回一个数组,这个数组中的对象已根据你指定的属性排好序。
说明
本攻略会使用到Person 对象。程序清单1-1 展示了Person 对象的类定义。虽然可以通过该攻略对字符串或数字对象排序,但只有当你使用NSSortDescriptor 处理自定义对象时,才会真正感受到它的强大功能。自定义类叫做Person,它有3 个属性,分别是firstName、lastName 与age。Person 类还有两个方法,分别是reportState 与initWithFirstName:lastName:andAge:,后者是自定义构造函数。
首先,创建Person 对象数组:
//Instantiate Person objects and add them all to an array:
Person *p1 = [[Person alloc] initWithFirstName:@"Rebecca"
lastName:@"Smith"
andAge:33];
Person *p2 = [[Person alloc] initWithFirstName:@"Albert"
lastName:@"Case"
andAge:24];
Person *p3 = [[Person alloc] initWithFirstName:@"Anton"
lastName:@"Belfey"
andAge:45];
Person *p4 = [[Person alloc] initWithFirstName:@"Tom"
lastName:@"Gun"
andAge:17];
Person *p5 = [[Person alloc] initWithFirstName:@"Cindy"
lastName:@"Lou"
andAge:6];
Person *p6 = [[Person alloc] initWithFirstName:@"Yanno"
lastName:@"Dirst"
andAge:76];
NSArray *listOfObjects = [NSArray arrayWithObjects:p1, p2, p3, p4, p5, p6, nil];
如果打印数组中的每个元素,对象就会以你将它们放到数组中时的顺序出现。如果想要根据每个人的年龄、姓与名排序数组,那么可以使用NSSortDescriptor 对象。需要为用于排序的每个Person 属性提供排序描述符:
//Create three sort descriptors and add to an array:
NSSortDescriptor *sd1 = [NSSortDescriptor sortDescriptorWithKey:@"age"
ascending:YES];
NSSortDescriptor *sd2 = [NSSortDescriptor sortDescriptorWithKey:@"lastName"
ascending:YES];
NSSortDescriptor *sd3 = [NSSortDescriptor sortDescriptorWithKey:@"firstName"
ascending:YES];
NSArray *sdArray1 = [NSArray arrayWithObjects:sd1, sd2, sd3, nil];
需要将属性名以字符串的形式传递进去并指定根据属性进行升序还是降序排序。最后,所有排序描述符需要放在数组中。数组中每个排序描述符的位置决定了对象的排序顺序。因此,如果希望数组先根据年龄,然后根据姓进行排序,那么确保先将与年龄对应的排序描述符添加进来,然后再将与姓对应的排序描述符添加进来。要想获得排好序的数组,请向待排序的数组发送sortedArrayUsingDescriptors:消息并将排序描述符数组作为参数传递进来:
NSArray *sortedArray1 = [listOfObjects sortedArrayUsingDescriptors:sdArray1];
要想查看结果,请使用makeObjectsPerformSelector:方法将排好序的数组中的每个对象的状态输出到日志中:
[sortedArray1 makeObjectsPerformSelector:@selector(reportState)];
这会以排序描述符(年龄、姓、名)指定的顺序将每个Person 对象的详细信息打印到日志中。参见程序清单1-1~1-3。
代码
程序清单1-1 Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property(strong) NSString *firstName;
@property(strong) NSString *lastName;
@property(assign) int age;
-(id)initWithFirstName:(NSString *)fName lastName:(NSString *)lName
andAge:(int)a;
-(void)reportState;
@end
程序清单1-2 Person.m
#import "Person.h"
@implementation Person
@synthesize firstName, lastName, age;
-(id)initWithFirstName:(NSString *)fName lastName:(NSString *)lName
andAge:(int)a{
self = [super init];
if (self) {
self.firstName = fName;
self.lastName = lName;
self.age = a;
}
return self;
}
-(void)reportState{
NSLog(@"This person's name is %@ %@ who is %i years old", firstName,
lastName, age);
}
@end
程序清单1-3 main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main (int argc, const char * argv[])
{
@autoreleasepool {
//Instantiate Person objects and add them all to an array:
Person *p1 = [[Person alloc] initWithFirstName:@"Rebecca"
lastName:@"Smith"
andAge:33];
Person *p2 = [[Person alloc] initWithFirstName:@"Albert"
lastName:@"Case"
andAge:24];
Person *p3 = [[Person alloc] initWithFirstName:@"Anton"
lastName:@"Belfey"
andAge:45];
Person *p4 = [[Person alloc] initWithFirstName:@"Tom"
lastName:@"Gun"
andAge:17];
Person *p5 = [[Person alloc] initWithFirstName:@"Cindy"
lastName:@"Lou"
andAge:6];
Person *p6 = [[Person alloc] initWithFirstName:@"Yanno"
lastName:@"Dirst"
andAge:76];
NSArray *listOfObjects = [NSArray arrayWithObjects:p1, p2, p3, p4,
p5, p6, nil];
NSLog(@"PRINT OUT ARRAY UNSORTED");
[listOfObjects makeObjectsPerformSelector:@selector(reportState)];
//Create three sort descriptors and add to an array:
NSSortDescriptor *sd1 = [NSSortDescriptor
sortDescriptorWithKey:@"age"ascending:YES];
NSSortDescriptor *sd2 = [NSSortDescriptor
sortDescriptorWithKey:@"lastName"ascending:YES];
NSSortDescriptor *sd3 = [NSSortDescriptor
sortDescriptorWithKey:@"firstName"ascending:YES];
NSArray *sdArray1 = [NSArray arrayWithObjects:sd1, sd2, sd3, nil];
NSLog(@"PRINT OUT SORTED ARRAY (AGE,LASTNAME,FIRSTNAME)");
NSArray *sortedArray1 = [listOfObjects
sortedArrayUsingDescriptors:sdArray1];
[sortedArray1 makeObjectsPerformSelector:@selector(reportState)];
NSArray *sdArray2 = [NSArray arrayWithObjects:sd2, sd1, sd3, nil];
NSArray *sortedArray2 = [listOfObjects
sortedArrayUsingDescriptors:sdArray2];
NSLog(@"PRINT OUT SORTED ARRAY (LASTNAME,FIRSTNAME,AGE)");
[sortedArray2 makeObjectsPerformSelector:@selector(reportState)];
}
return 0;
}
使用
要想使用上述代码,需要为Person 类创建文件。这是一个Objective-C 类,可以使用Xcode 文件模板创建。Person 类必须导入到main.m 文件的代码中(对于Mac 命令行应用)。构建并运行项目,然后通过控制台日志查看数组的排序结果:
PRINT OUT ARRAY UNSORTED
This person's name is Rebecca Smith who is 33 years old
This person's name is Albert Case who is 24 years old
This person's name is Anton Belfey who is 45 years old
This person's name is Tom Gun who is 17 years old
This person's name is Cindy Lou who is 6 years old
This person's name is Yanno Dirst who is 76 years old
PRINT OUT SORTED ARRAY (AGE,LASTNAME,FIRSTNAME)
This person's name is Cindy Lou who is 6 years old
This person's name is Tom Gun who is 17 years old
This person's name is Albert Case who is 24 years old
This person's name is Rebecca Smith who is 33 years old
This person's name is Anton Belfey who is 45 years old
This person's name is Yanno Dirst who is 76 years old
PRINT OUT SORTED ARRAY (LASTNAME,FIRSTNAME,AGE)
This person's name is Anton Belfey who is 45 years old
This person's name is Albert Case who is 24 years old
This person's name is Yanno Dirst who is 76 years old
This person's name is Tom Gun who is 17 years old
This person's name is Cindy Lou who is 6 years old
This person's name is Rebecca Smith who is 33 years old