我有一个充满了我创建的名为“问题”的NSObjects数组。 每个问题的一个属性是它属于哪个级别。 如果用户选择了玩2级,我想获得所有具有.level属性为2的问题。现在我正在循环查看所有问题以找到匹配项,但这需要~2秒才能在iPad上运行3 /新iPad设备。有没有更快的方法来处理这样的情况?
int goThrough = 0;
do {
Question *currentQuestion = [allQs objectAtIndex:(goThrough)];
if (currentQuestion.level == levelChosen) {
[questions addObject:currentQuestion];
}
goThrough++;
} while (goThrough < [allQs count]);
非常感谢您的帮助!
答案 0 :(得分:5)
如果您必须定期按级别组织问题,那么为什么不按级别组织所有问题。创建数组字典。每个键,如果级别和每个数组是该级别的问题列表。你这样做一次,将问题提升到一个水平变得微不足道。
答案 1 :(得分:0)
我建议使用NSArray方法enumerateObjectsUsingBlock或其中一个变体。甚至有变体将同时循环遍历数组元素。你可能需要使用一个锁来向你的问题数组中添加元素,因为我怀疑NSMutableArray的addObject方法是否是线程安全的。
您应该针对具有锁定的并发版本测试非并发版本,以查看哪个版本更快。哪种方法更快将取决于allQs数组中有多少对象属于当前级别。如果只有少数属于,则断言锁定的代码不会经常触发,并发性的好处将超过断言锁定的时间代价。如果allQs数组中的大多数对象与所选级别匹配,代码将最终花费大量时间断言锁,并且并发线程仍将等待其他线程释放锁。
修改后的代码可能如下所示:
单线程版本:
[allQs enumerateObjectsUsingBlock:
^(Question *currentQuestion, NSUInteger index, BOOL *stop)
{
if (currentQuestion.level == levelChosen)
[questions addObject:currentQuestion];
}
];
并发版本:
[allQs enumerateObjectsWithOptions:
NSEnumerationConcurrent
usingBlock:
^(Question *currentQuestion, NSUInteger index, BOOL *stop)
{
if (currentQuestion.level == levelChosen)
@synchronized
{
[questions addObject:currentQuestion];
}
}
];
实际上,现在我考虑一下,通过首先使用indicesOfObjectsWithOptions:passingTest对数组进行并发传递,您可能会获得更快的性能。在该传递中,您将构建与当前级别匹配的所有对象的NSIndexSet。然后在一次传递中,您将这些元素提取到另一个数组中:
NSIndexSet *questionIndexes = [allQs indexesOfObjectsWithOptions: NSEnumerationConcurrent
usingBlock:
^(Question *currentQuestion, NSUInteger index, BOOL *stop)
{
return (currentQuestion.level == levelChosen)
}
];
questions = [allQs objectsAtIndexes: questionIndexes];
另一张海报指出,你最好提前提升你的问题阵列。如果这对你的程序流程有效,那就更好了,因为根本不过滤你的数组总是比最高度优化的过滤代码更快。
答案 2 :(得分:0)
你总是可以使用快速枚举(除非你打算改变对象是枚举集合的最快方法)。像这样:
for (Question *thisQuestion in allQs) {
if (thisQuestion.level == levelChosen)
[questions addObject:thisQuestion];
}
}
由于您没有改变正在迭代的集合(allQs
),这样可以正常工作并且比使用enumerateObjectsUsingBlock
更快。如果您需要迭代的数组索引(allQs
),请使用enumerateObjectsUsingBlock
。
答案 3 :(得分:0)
我暂时无法访问Mac,但你可以尝试一下:
[allQs enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger index, BOOL *stop) {
Question *currentQuestion = [allQs objectAtIndex:index];
if (currentQuestion.level == levelChosen) {
[questions addObject:currentQuestion];
}
}
这将使用您设备的所有核心,因此它可以快两倍
答案 4 :(得分:0)
似乎缺少一个简单的答案。如果要过滤数组的对象只剩下某些对象,-filteredArrayUsingPredicate:
就是你想要的。它可以非常简单地完成。
NSPredicate *p = [NSPredicate predicateWithBlock:^(Question *aQuestion, NSDictionary *bindings){
return (aQuestion.level==2);
}];
NSArray *filteredArray = [originalArray filteredArrayUsingPredicate:p];